linux下C语言的多线程编程的详细介绍

这篇文章主要介绍了linux下c语言的多线程编程,需要的朋友可以参考下

我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 

多线程的一些小知识:

一个应用程序可以启动若干个线程。

线程(Lightweight Process,LWP),是程序执行的最小单元。

立即学习“C语言免费学习笔记(深入)”;

一般一个最简单的程序最少会有一个线程,就是程序本身,也就是主函数(单线程的进程可以简单的认为只有一个线程的进程)

 一个线程阻塞并不会影响到另外一个线程。

多线程的进程可以尽可能的利用系统CPU资源。

1创建线程

先上一段在一个进程中创建一个线程的简单的代码,然后慢慢深入。

#include#include#include#include#includevoid * func(void * arg){ printf("func run...n"); return NULL;}int main(){ pthread_t t1; int err = pthread_create(&t1,NULL,func,NULL); if(err!=0) {  printf("thread_create Failed:%sn",strerror(errno)); }else{  printf("thread_create successn"); } sleep(1); return EXIT_SUCCESS;}int pthread_create(pthread_t *thread,const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

在main函数里面我们调用上面的函数进行创建一个线程。

函数参数:

  第一个参数:pthread_t代表创建线程的唯一标识,是一个结构体,需要我们创建好后,将这个结构体的指针传递过去。

  第二个参数:pthread_attr_t,代表创建这个线程的一些配置,比如分配栈的大小等等。。一般我们可以填NULL,代表默认的创建线程的配置

  第三个参数:代表一个函数的地址,创建线程时,会调用这个函数,函数的返回值是void*,函数的参数也是void*,一般格式就像void * func(void * arg){}

  第四个参数:代表调用第三个函数传递的参数

函数返回值:

  函数成功返回0,如果不等于0则代表函数调用失败,此时通过strerror(errno)可以打印出具体的错误。

  注意:每个线程都拥有一份errno副本,不同的线程拥有不同的errno

最后通过gcc编译

gcc 1createthread.c -c -o 1createthread.ogcc 1createthread.o -o thr1 -lpthread

编译的时候需要加上-lpthread 用来链接libpthread.so动态库,不然会提示找不到function

函数调用返回结果

linux下C语言的多线程编程的详细介绍

问题:为什么调用sleep函数

答:可能新创建的线程还没运行到打印的方法主线程就结束了,而主线程结束,所有线程都会结束了。

2线程挂起

有时候我们在一个线程中创建了另外一个线程,主线程要等到创建的线程返回了,获取该线程的返回值后主线程才退出。这个时候就需要用到线程挂起。

int pthread_join(pthread_t th, void **thr_return);。

pthread_join函数用于挂起当前线程,直至th指定的线程终止为止。

#include#include#include#include#includevoid * func(void * arg){ int i=0; for(;i<5;i++) {  printf("func run%dn",i);  sleep(1); } int * p = (int *)malloc(sizeof(int)); *p=11; return p;}int main(){ pthread_t t1,t2; int err = pthread_create(&t1,NULL,func,NULL); if(err!=0) {  printf("thread_create Failed:%sn",strerror(errno)); }else{  printf("thread_create successn"); } void *p=NULL; pthread_join(t1,&p); printf("线程退出:code=%dn",*(int*)p); return EXIT_SUCCESS;}

函数执行结果

linux下C语言的多线程编程的详细介绍

我们主函数一直在等待创建的线程执行完,并且得到了线程执行结束的返回值

3线程终止

进程终止时exit()函数,那么线程终止是什么呢?

线程终止的三种情况:

线程只是从启动函数中返回,返回值是线程的退出码。

线程可以被同一进程中的其他线程取消。

线程调用pthread_exit。

豆包AI编程 豆包AI编程

豆包推出的AI编程助手

豆包AI编程 483 查看详情 豆包AI编程

#include#include#include#include#includevoid * func(void * arg){ int i=0; while(1) {  if(i==10)  {   int * p = (int *)malloc(sizeof(int));   *p=11;   pthread_exit(p);  }  printf("fun run %dn",i++);  sleep(1); } return NULL;}int main(){ pthread_t t1,t2; int err = pthread_create(&t1,NULL,func,NULL); if(err!=0) {  printf("thread_create Failed:%sn",strerror(errno)); }else{  printf("thread_create successn"); } void *p=NULL; pthread_join(t1,&p); printf("线程退出:code=%d",*(int*)p); return EXIT_SUCCESS;}void pthread_exit(void *arg);

pthread_exit函数的参数就跟正常线程结束return的使用时一样的,都会被等待它结束的主线程获取到。

函数运行结果:

linux下C语言的多线程编程的详细介绍

4线程分离

int pthread_detach(pthread_t th);

pthread_detach函数使线程处于被分离状态。

如果不等待一个线程,同时对线程的返回值不感兴趣,可以设置这个线程为被分离状态,让系统在线程退出的时候自动回收它所占用的资源。

一个线程不能自己调用pthread_detach改变自己为被分离状态,只能由其他线程调用pthread_detach。

5线程取消

int pthread_cancel(pthread_t th);

pthread_cancel函数允许一个线程取消th指定的另一个线程。

函数成功,返回0,否则返回非0。

#include#include#include#include#includevoid * func1(void * arg){ while(1) {  printf("fun run...n");  sleep(1); } return NULL;}int main(){ pthread_t t1; if(pthread_create(&t1,NULL,func1,NULL)!=0) {  printf("thread_create Failed:%sn",strerror(errno));  return -1; } sleep(5); pthread_cancel(t1); pthread_join(t1,NULL); return EXIT_SUCCESS;}

 函数执行结果:

linux下C语言的多线程编程的详细介绍

上面我们说过创建一个线程函数pthread_create的第二个参数,用来决定创建线程的一些初始化状态,这里我们 举个例子,改线程一创建就是分离状态的线程(

上面介绍了pthread_detach函数的概念,可以通过pthread_attr_t在创建线程的时候就指定线程属性为detach,而不用创建以后再去修改线程属性。
)

先上一段代码:

#include#include#include#include#includevoid * func(void * arg){ int i=0; for(;i<5;i++) {  printf("func run%dn",i);  sleep(1); } int * p = (int *)malloc(sizeof(int)); *p=11; return p;}int main(){ pthread_t t1; pthread_attr_t attr;//申明一个attr的结构体 pthread_attr_init(&attr);//初始化结构体 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程为分离线程 int err = pthread_create(&t1,&attr,func,NULL); if(err!=0) {  printf("thread_create Failed:%sn",strerror(errno)); }else{  printf("thread_create successn"); } pthread_attr_destroy(&attr); pthread_join(t1,NULL); printf("主线程退出n"); return EXIT_SUCCESS;}

pthread_attr_t就是我们要传入的参数的结构体,一般申明的步骤有

1,申明一个pthread_attr_t对象

2,函数pthread_attr_init初始化attr结构。

3,设置线程的一些属性,比如pthread_attr_setdetachstate函数就是设置该线程创建的时候为正常状态还是分离状态。

4,函数pthread_attr_destroy释放attr内存空间

pthread_attr_setdetachstate把线程属性设置为下面两个合法值之一:

值

说明

PTHREAD_CREATE_DETACHED

设置线程为分离状态

PTHREAD_CREATE_JOINABLE

设置线程为正常状态

上面函数运行结果:

linux下C语言的多线程编程的详细介绍

因为线程是个分离状态的,所以pthread_join挂起会失效,主线程很快运行结束,程序也就结束了,创建的线程还没来得及运行

线程同步

有时候我们多个线程处理订单扣减库存会遇到这样的问题,两个线程同时进入一段代码先查询库存,两个都查出来为还剩一件库存,第一个线程用掉这个库存后,将库存变为0,但是第二个线程刚才也查出来为1了,所以他还认为有库存,

这个时候操作就会引发我们想不到的意外,库存变为负数了!!所以这个时候就需要使用线程的同步!!

先上一段代码看看效果:

#include#include#include#include#include#include#includevoid * func(void * arg){ int threadno =*(int*)arg; int i=0; for(;i<10;i++) {  printf("%d thread%d n",threadno,i);  sleep(1); } return NULL;}int main(){ pthread_t t1,t2; int i1=1,i2=2; pthread_create(&t1,NULL,func,&i1); pthread_create(&t2,NULL,func,&i2); pthread_join(t1,NULL); pthread_join(t2,NULL); printf("主线程退出n"); return EXIT_SUCCESS;}

函数运行结果:

linux下C语言的多线程编程的详细介绍

可以看到两个线程是没有规律的争相处理的,如果这段代码是扣减库存就完蛋啦!,所以我们要对这段代码进行加锁,同一时刻只能有一个线程进入操作!

先上代码:

#include#include#include#include#includepthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void * func(void * arg){ pthread_mutex_lock(&mutex);//对mutex加锁,其他线程进入后将会挂起,知道这个锁被解锁 int threadno =*(int*)arg; int i=0; for(;i<10;i++) {  printf("%d thread%d n",threadno,i);  sleep(1); } pthread_mutex_unlock(&mutex); return NULL;}int main(){ pthread_t t1,t2; int i1=1,i2=2; pthread_create(&t1,NULL,func,&i1); pthread_create(&t2,NULL,func,&i2); pthread_join(t1,NULL); pthread_join(t2,NULL); printf("主线程退出n"); return EXIT_SUCCESS;}

函数运行结果:

linux下C语言的多线程编程的详细介绍

可以看到第二个线程先进入后一直运行结束,对mutex解锁后,第一个线程才能进方法里面运行!否则会挂起,一直等到锁被解锁!

PTHREAD_MUTEX_INITIALIZER是初始化一个快速锁的宏定义。

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

加锁解锁函数:

int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);

总结

以上就是linux下C语言的多线程编程的详细介绍的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/284476.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Windows Update服务启动弹出“拒绝访问的解决方案
上一篇 2026年10月19日 02:27:12
神匠崛起:铁匠铺终极改造与镔铁炼金术
下一篇 2026年9月24日 07:37:08

相关推荐

  • 微软确认 Win10 21H2 更新已大规模推送,不强制用户升级Win11

    微软确认 Win10 21H2 更新已大规模推送,不强制用户升级Win11微软确认 Win10 21H2 更新已大规模推送,不强制用户升级Win11微软确认 Win10 21H2 更新已大规模推送,不强制用户升级Win11微软确认 Win10 21H2 更新已大规模推送,不强制用户升级Win11

    早在2021年11月,微软便开始面向符合条件的设备推送windows 10的2021年11月更新(即版本21h2)。尽管windows 10的技术支持将持续至2025年10月,但微软已明确表示,未来不会再为windows 10引入全新特性。与此同时,windows 11则会每年迎来一次重要的功能更新…

    2026年10月19日 • 用户投稿
    100
  • Linux expect 的安装教程

    expect是一个免费的编程工具语言,用来实现自动和交互式任务进行通信,而无需人的干预。使用它系统管理员 的可以创建脚本用来实现对命令或程序提供输入,而这些命令和程序是期望从终端(terminal)得到输入,一般来说这些输入都需要手工输入进行的。 expect则可以根据程序的提示模拟标准输入提供给程…

    2026年10月19日
    100
  • 路由器192.168.1.253的登录密码忘了怎么办?初始是多少?

    路由器192.168.1.253的登录密码忘了怎么办?初始是多少?路由器192.168.1.253的登录密码忘了怎么办?初始是多少?路由器192.168.1.253的登录密码忘了怎么办?初始是多少?路由器192.168.1.253的登录密码忘了怎么办?初始是多少?

    路由器登录密码忘记后最直接有效的方法是恢复出厂设置,通过通电状态下长按reset键5到10秒,待指示灯闪烁后松开,等待重启;2. 重置后使用默认ip(如192.168.1.1或192.168.0.1)和默认用户名密码(如admin/admin)登录,具体信息可查看路由器底部标签;3. 登录后按照设置…

    2026年10月19日 • 用户投稿
    200
  • 教你如何用linux设置服务器自动重启

    作为程序员的我们都用过linux,我们都知道linux主要是做服务器用的,本篇文章我们就来教大家一种linux下设置服务器自动重启的技巧,希望对大家工作有用。 步骤如下: 每个月1号凌晨3点自动重启 步骤如下: 1、用root帐号登陆; 2、打开终端窗口; 3、输入”crontab -e…

    2026年10月19日
    300
  • php workerman

    php workermanphp workermanphp workermanphp workerman

    PHP Workerman 是一个高并发、低延迟、跨平台的 PHP 并发网络框架,特点包括:事件驱动、异步非阻塞、高效内存管理、使用协程技术,应用场景涉及即时通讯、网络爬虫、数据流处理、API 网关、微服务等。 什么是 PHP Workerman? PHP Workerman 是一个基于 PHP 的…

    2026年10月19日 • 用户投稿
    300
  • linux vlan配置详解

    linux vlan配置详解linux vlan配置详解linux vlan配置详解linux vlan配置详解

    本文主要给大家介绍了关于linux虚拟网络设备之vlan配置的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,希望能帮助到大家。 简介 VLAN是网络栈的一个附加功能,且位于下两层。首先来学习Linux中网络栈下两层的实现,再去看如何把VLAN这个功能附加上去。…

    2026年10月19日 • 用户投稿
    100
  • VSCode怎样使用查找功能快速定位内容 VSCode新手查找功能的使用方法与技巧​

    VSCode怎样使用查找功能快速定位内容 VSCode新手查找功能的使用方法与技巧​VSCode怎样使用查找功能快速定位内容 VSCode新手查找功能的使用方法与技巧​VSCode怎样使用查找功能快速定位内容 VSCode新手查找功能的使用方法与技巧​VSCode怎样使用查找功能快速定位内容 VSCode新手查找功能的使用方法与技巧​

    vscode查找功能的核心答案是:1. 使用ctrl+f/cmd+f在当前文件中查找,输入关键词即可高亮所有匹配项并逐个浏览;2. 点击搜索框的.图标启用正则表达式模式,如输入^console.log.$查找以console.log开头的行,注意特殊字符需转义;3. 使用ctrl+shift+f/c…

    2026年10月19日 • 用户投稿
    100
  • Linux终极渗透测试命令总结

    本文主要和大家分享linux终极渗透测试命令总结,如下是一份 linux 机器的渗透测试备忘录,是在后期开发期间或者执行命令注入等操作时的一些典型命令,设计为测试人员进行本地枚举检查之用。 命令 描述 netstat -tulpn在 Linux 中显示对应了进程ID(PID)的网络端口。watch …

    2026年10月19日
    100
  • Linux调试工具GDB使用教程

    Linux调试工具GDB使用教程Linux调试工具GDB使用教程Linux调试工具GDB使用教程Linux调试工具GDB使用教程

    本文主要介绍了linux调试工具gdb使用简易教程,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下,希望能帮助到大家。 声明:本博客内容是由本人经过实验楼教程整理得来。 GDB的相关概念 GDB, 是 The GNU Project Debugger 的缩写, 是 Linux 下功能全…

    2026年10月19日 • 用户投稿
    100
  • docker容器的启动(docker容器启动时间)

    大家好,欢迎再次光临,我是你们的朋友全栈君。 当我们使用-d参数启动容器时,容器会进入后台运行,用户无法直接看到容器内的信息或进行操作。 此时,若需要进入容器进行操作,有多种方法可供选择,包括使用Docker官方提供的attach或exec命令,以及第三方工具nsenter。 1、attach命令 …

    2026年10月18日
    100
  • linux下svn常用命令分享

    本文主要和大家分享linux下svn常用命令,希望能帮助到大家。 1、将文件checkout到本地目录svn checkout path(path是服务器上的目录)例如:svn checkout svn://192.168.1.1/pro/domain简写:svn co 2、往版本库中添加新的文件s…

    2026年10月18日
    100
  • Linux下安装Redis、MongoDB

    安装redis yum -y install epel-release #安装epel仓库,里面包含redis的yum仓库yum -y install redis #安装redisservice redis start #启动redis服务systemctl enable redis #开机自启re…

    2026年10月18日
    100
  • 如何一键打开无痕模式:谷歌浏览器无痕浏览窗口教学

    如何一键打开无痕模式:谷歌浏览器无痕浏览窗口教学如何一键打开无痕模式:谷歌浏览器无痕浏览窗口教学如何一键打开无痕模式:谷歌浏览器无痕浏览窗口教学如何一键打开无痕模式:谷歌浏览器无痕浏览窗口教学

    本文将聚焦于如何实现“一键”开启谷歌浏览器的无痕模式,为您提供最高效的操作教学。我们将讲解利用键盘快捷键即时调出无痕窗口的方法,并进一步介绍如何通过创建一个专用的桌面快捷方式,实现真正意义上的一键启动无痕浏览,让您随时都能快速进入隐私浏览状态。 立即进入“免费看电影的软件☜☜☜☜☜点击进入”; 什么…

    2026年10月18日 • 用户投稿
    100
  • linux下怎么安装composer并改源

    linux下怎么安装composer并改源linux下怎么安装composer并改源linux下怎么安装composer并改源linux下怎么安装composer并改源

    本文由composer教程栏目给大家介绍关于linux下如何安装composer并改源,希望对需要的朋友有所帮助! linux下安装composer并改源 先下载composer.phar包到服务器上,可以使用wget,curl,或者ftp上传 配置php全局变量,测试composer是否正常 发送…

    2026年10月18日 • 用户投稿
    600
  • linux下的phpize扩展安装实例详解

    linux下的phpize扩展安装实例详解linux下的phpize扩展安装实例详解linux下的phpize扩展安装实例详解linux下的phpize扩展安装实例详解

    linux系统中,php安装成功后,在bin目录下会生成一个名叫phpize的可执行脚本,这个脚本的用途是动态安装php扩展模块。 使用phpize脚本安装php扩展模块的好处:在安装php时没有安装的扩展,可以在以后随时安装上,且不需要重新安装PHP。   安装步骤: 1、切换到扩展模块目录 立即…

    2026年10月18日 • 用户投稿
    100
  • 谷歌浏览器怎么开启无痕浏览 谷歌浏览器隐私窗口完整步骤

    谷歌浏览器怎么开启无痕浏览 谷歌浏览器隐私窗口完整步骤谷歌浏览器怎么开启无痕浏览 谷歌浏览器隐私窗口完整步骤谷歌浏览器怎么开启无痕浏览 谷歌浏览器隐私窗口完整步骤谷歌浏览器怎么开启无痕浏览 谷歌浏览器隐私窗口完整步骤

    本文将为您提供一份谷歌浏览器开启无痕浏览的完整步骤指南。通过这篇教程,您将学会如何在桌面电脑和移动设备上轻松启动隐私窗口,从而在浏览网页时不留下本地痕迹。下文将对整个操作过程进行详细分解,确保您能顺利掌握。 立即进入“免费看电影的软件☜☜☜☜☜点击进入”; 什么是无痕模式? 无痕模式,也称为隐私窗口…

    2026年10月18日 • 用户投稿
    100
  • linux之Centos7系统加固知识点小结

    本文主要给大家详细介绍了linux中centos7系统加固的相关知识点,希望能帮助到大家。 注意:此教程的云服务器以centos7以上为例,云服务器于阿里云购买 其他服务商的云服务器配置大同小异 建议:linux的服务器不建议安装图形化工具,因为占内存,占带宽,占资源,弊远大于利 手动更新系统: y…

    2026年10月18日
    100
  • Linux中Apache设置压缩及缓存的方法实例

    本文主要和大家分享linux中apache设置压缩及缓存的方法实例,希望能帮助到大家。 压缩文件: 编辑apache模块 vim /etc/httpd/conf.modules.d/00-base.conf 确保以下三个模块没有被注释 LoadModule headers_module module…

    2026年10月18日
    000
  • 168.77.1路由器流量监控 192.168.77.1端口映射配置(隔离模式)

    168.77.1路由器流量监控 192.168.77.1端口映射配置(隔离模式)168.77.1路由器流量监控 192.168.77.1端口映射配置(隔离模式)168.77.1路由器流量监控 192.168.77.1端口映射配置(隔离模式)168.77.1路由器流量监控 192.168.77.1端口映射配置(隔离模式)

    要监控192.168.77.1路由器流量并配置端口映射,需登录其管理界面操作;1. 流量监控通过“流量统计”或“qos”等功能查看wan口数据,但可能存在统计不准问题,因多数路由器仅记录公网流量且受硬件性能限制;2. 端口映射在“虚拟服务器”或“nat设置”中配置,需指定外网端口、内网ip(如192…

    2026年10月18日 • 用户投稿
    300
  • Linux crond不执行的原因

    为了定时监控Linux系统CPU、内存、负载的使用情况,写了Linux Shell脚本,当达到一定值得时候,定时发送邮件通知。但是,让crond来周期性执行脚本发送邮件通知时,遇到了问题,在crontab -e里面加入了执行脚本之后,发现脚本并没有执行。 可是,通过手动执行Shell脚本命令(./m…

    用户投稿 2026年10月18日
    300

发表回复

登录后才能评论
关注微信