千家信息网

Linux多线程编程的示例分析

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍了Linux多线程编程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1 线程基本知识进程是资源管理的基本单元
千家信息网最后更新 2026年11月03日Linux多线程编程的示例分析

这篇文章主要介绍了Linux多线程编程的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

1 线程基本知识

进程是资源管理的基本单元,而线程是系统调度的基本单元,线程是操作系统能够进行调度运算的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

一个进程在某一个时刻只能做一件事情,有了多个控制线程以后,在程序的设计成在某一个时刻能够做不止一件事,每个线程处理独自的任务。

需要注意的是:即使程序运行在单核处理器上,也能够得到多线程编程模型的好处。处理器的数量并不影响程序结构,所以不管处理器个数多少,程序都可以通过线程得以简化。

linux操作系统使用符合POSIX线程作为系统标准线程,该POSIX线程标准定义了一整套操作线程的API。

2. 线程标识

与进程有一个ID一样,每个线程有一个线程ID,所不同的是,进程ID在整个系统中是唯一的,而线程是依附于进程的,其线程ID只有在所属的进程中才有意义。线程ID用pthread_t表示。

//pthread_self直接返回调用线程的IDinclude pthread_t pthread_self(void);

判断两个线程ID的大小是没有任何意义的,但有时可能需要判断两个给定的线程ID是否相等,使用以下接口:

//pthread_equal如果t1和t2所指定的线程ID相同,返回0;否则返回非0值。include int pthread_equal(pthread_t t1, pthread_t t2);

3. 线程创建

一个线程的生命周期起始于它被创建的那一刻,创建线程的接口:

#include int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

函数参数:

thread(输出参数),由pthread_create在线程创建成功后返回的线程句柄,该句柄在后续操作线程的API中用于标志该新建的线程; start_routine(输入参数),新建线程的入口函数; arg(输入参数),传递给新线程入口函数的参数; attr(输入参数),指定新建线程的属性,如线程栈大小等;如果值为NULL,表示使用系统默认属性。

函数返回值:

成功,返回0; 失败,返回相关错误码。

需要注意:

1.主线程,这是一个进程的初始线程,其入口函数为main函数。
2.新线程的运行时机,一个线程被创建之后有可能不会被马上执行,甚至,在创建它的线程结束后还没被执行;也有可能新线程在当前线程从pthread_create前就已经在运行,甚至,在pthread_create前从当前线程返回前新线程就已经执行完毕。

程序实例:

#include #include #include #include void printids(const char *s){ pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); printf("%s, pid %lu tid %lu (0x%lx)\n",s,(unsigned long)pid,(unsigned long)tid, (unsigned long)tid);}void *thread_func(void *arg){ printids("new thread: "); return ((void*)0);}int main() { int err; pthread_t tid; err = pthread_create(&tid,NULL,thread_func,NULL); if (err != 0) {  fprintf(stderr,"create thread fail.\n"); exit(-1);  } printids("main thread:"); sleep(1);  return 0;}

注意上述的程序中,主线程休眠一秒,如果不休眠,则主线程不休眠,则其可能会退出,这样新线程可能不会被运行,我自己注释掉sleep函数,发现好多次才能让新线程输出。

编译命令:

gcc -o thread thread.c -lpthread

运行结果如下:

main thread:, pid 889 tid 139846854309696 (0x7f30a212f740)new thread: , pid 889 tid 139846845961984 (0x7f30a1939700)

可以看到两个线程的进程ID是相同的。其共享进程中的资源。

4. 线程终止

线程的终止分两种形式:被动终止和主动终止

被动终止有两种方式:

1.线程所在进程终止,任意线程执行exit、_Exit或者_exit函数,都会导致进程终止,从而导致依附于该进程的所有线程终止。
2.其他线程调用pthread_cancel请求取消该线程。

主动终止也有两种方式:

1.在线程的入口函数中执行return语句,main函数(主线程入口函数)执行return语句会导致进程终止,从而导致依附于该进程的所有线程终止。
2.线程调用pthread_exit函数,main函数(主线程入口函数)调用pthread_exit函数, 主线程终止,但如果该进程内还有其他线程存在,进程会继续存在,进程内其他线程继续运行。

线程终止函数:

include void pthread_exit(void *retval);

线程调用pthread_exit函数会导致该调用线程终止,并且返回由retval指定的内容。
注意:retval不能指向该线程的栈空间,否则可能成为野指针!

5. 管理线程的终止

5.1 线程的连接

一个线程的终止对于另外一个线程而言是一种异步的事件,有时我们想等待某个ID的线程终止了再去执行某些操作,pthread_join函数为我们提供了这种功能,该功能称为线程的连接:

include int pthread_join(pthread_t thread, void **retval);

参数说明:

thread(输入参数),指定我们希望等待的线程 retval(输出参数),我们等待的线程终止时的返回值,就是在线程入口函数中return的值或者调用pthread_exit函数的参数

返回值:

成功时,返回0 错误时,返回正数错误码

当线程X连接线程Y时,如果线程Y仍在运行,则线程X会阻塞直到线程Y终止;如果线程Y在被连接之前已经终止了,那么线程X的连接调用会立即返回。

连接线程其实还有另外一层意义,一个线程终止后,如果没有人对它进行连接,那么该终止线程占用的资源,系统将无法回收,而该终止线程也会成为僵尸线程。因此,当我们去连接某个线程时,其实也是在告诉系统该终止线程的资源可以回收了。

注意:对于一个已经被连接过的线程再次执行连接操作, 将会导致无法预知的行为!

5.2 线程的分离

有时我们并不在乎某个线程是不是已经终止了,我们只是希望如果某个线程终止了,系统能自动回收掉该终止线程所占用的资源。pthread_detach函数为我们提供了这个功能,该功能称为线程的分离:

#include int pthread_detach(pthread_t thread);

默认情况下,一个线程终止了,是需要在被连接后系统才能回收其占有的资源的。如果我们调用pthread_detach函数去分离某个线程,那么该线程终止后系统将自动回收其资源。

/** 文件名: thread_sample1.c* 描述:演示线程基本操作*/#include #include #include #include /*子线程1入口函数*/void *thread_routine1(void *arg){ fprintf(stdout, "thread1: hello world!\n"); sleep(1); /*子线程1在此退出*/ return NULL;}/*子线程2入口函数*/void *thread_routine2(void *arg){ fprintf(stdout, "thread2: I'm running...\n"); pthread_t main_thread = (pthread_t)arg; /*分离自我,不能再被连接*/ pthread_detach(pthread_self()); /*判断主线程ID与子线程2ID是否相等*/ if (!pthread_equal(main_thread, pthread_self())) {  fprintf(stdout, "thread2: main thread id is not equal thread2\n"); } /*等待主线程终止*/ pthread_join(main_thread, NULL); fprintf(stdout, "thread2: main thread exit!\n"); fprintf(stdout, "thread2: exit!\n"); fprintf(stdout, "thread2: process exit!\n"); /*子线程2在此终止,进程退出*/ pthread_exit(NULL);}int main(int argc, char *argv[]){ /*创建子线程1*/ pthread_t t1; if (pthread_create(&t1, NULL, thread_routine1, NULL)!=0) {  fprintf(stderr, "create thread fail.\n");  exit(-1); } /*等待子线程1终止*/ pthread_join(t1, NULL); fprintf(stdout, "main thread: thread1 terminated!\n\n"); /*创建子线程2,并将主线程ID传递给子线程2*/ pthread_t t2; if (pthread_create(&t2, NULL, thread_routine2, (void *)pthread_self())!=0) {  fprintf(stderr, "create thread fail.\n");  exit(-1); } fprintf(stdout, "main thread: sleeping...\n"); sleep(3); /*主线程使用pthread_exit函数终止,进程继续存在*/ fprintf(stdout, "main thread: exit!\n"); pthread_exit(NULL);  fprintf(stdout, "main thread: never reach here!\n"); return 0;}

最终的执行结果如下:

thread1: hello world!main thread: thread1 terminated!main thread: sleeping...thread2: I'm running...thread2: main thread id is not equal thread2main thread: exit!thread2: main thread exit!thread2: exit!thread2: process exit!

感谢你能够认真阅读完这篇文章,希望小编分享的"Linux多线程编程的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

线程 函数 进程 系统 参数 入口 资源 运行 程序 功能 篇文章 处理 输入 编程 成功 两个 处理器 错误 休眠 输出 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 蓝思科技飞鸽互联网 美国互联网保险保险科技 北京互联网科技有限公司 深圳互联网络科技有限公司 多迪互联网科技有限公司 华中科技有哪些互联网大佬 互联网企业和科技型企业 互联网科技创新服务 互联网校园科技培训 黑科技闪耀互联网之光 深圳育鹏互联网科技有限公司招聘 健康食品互联网创新科技园项目 中国科技创新与世界互联网大会 996高科技互联网公司 洛阳共同富裕互联网科技有限公司 高科技互联网发展前景如何 互联网金融科技元年 互联网金融科技公司的优势 互联网公司高科技产品 福仕德教育科技互联网 哈尔滨大商圈互联网科技有限公司 华服互联网科技怎么样 华宇互联网科技 卓越科技(互联网 ) 菲比寻常互联网科技 世界互联网科技公司市值排名 卓翼科技产业互联网合作 徐州市互联网科技有限公司 互联网硬科技公司 重庆科技产业互联网有哪些
0