线程控制原语小结
2018-03-20 21:39
204 查看
在本篇博客中主要总结一下linux下,线程的一些控制原语。
在Linux环境下,所有线程特点,失败均直接返回错误号。所以我们可以利用strerror()将错误信号所代表的具体错误打印出来。参数为发生错误所返回的错误信号
4000
。例如:
参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数4:线程主函数执行期间所使用的参数。
(2)、pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元。线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self()可以获得当前线程的id。
(2)、pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
retval:存储线程结束状态。
1、如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
2、如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
3、如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
4、如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资源仍存于系统中,导致内核认为该进程仍存在。
取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write等等。(执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。)
可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用pthreestcancel函数自行设置一个取消点。
(2)、被取消的线程, 退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是-1。可在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join()回收时,得到的返回值为-1。
2.避免僵尸线程
①、pthread_join()
②、pthread_detach()
③、pthread_create指定分离属性
被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;
3.malloc和mmap申请的内存可以被其他线程释放
4.应避免在多线程模型中调用fork除非,马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit
5.信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制。
6、在编译链接加 -pthread ,因为线程库属于第三方库,gcc默认加载标准库。
在Linux环境下,所有线程特点,失败均直接返回错误号。所以我们可以利用strerror()将错误信号所代表的具体错误打印出来。参数为发生错误所返回的错误信号
4000
。例如:
ret = pthread_create(&tid ,NULL ,thrd_func ,NULL); if(ret != 0) { fprintf(stderr , "pthread_create error : %s \n", strerror(ret)); exit(1); }
1、pthread_create()函数
作用
创建一个新线程。 其作用,对应进程中fork() 函数。原形
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
返回值
返回值:成功:0; 失败:错误号 (Linux环境下,所有线程特点,失败均直接返回错误号)。说明
参数1:传出参数,保存系统为我们分配好的线程ID参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数4:线程主函数执行期间所使用的参数。
注意
(1)、在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的回调函数start_routine决定。start_routine返回时,这个线程就退出了。(2)、pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元。线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self()可以获得当前线程的id。
2、pthread_self()函数
作用
获取当前线程ID。其作用对应进程中 getpid() 函数。原形
pthread_t pthread_self(void);
返回值
成功:返回线程ID; 失败:错误号;说明
线程ID:pthread_t类型,本质:在Linux下为无符号整数(%lu),其他系统中可能是结构体实现;线程ID是进程内部,识别标志。(两个进程间,线程ID允许相同)。注意
不应使用全局变量 pthread_t tid,在子线程中通过pthread_create传出参数来获取线程ID,而应使用pthread_self。3、pthread_exit()函数
作用
将单个线程退出原形
void pthread_exit(void *retval)
返回值
成功:0; 失败:无;说明
retval表示线程退出状态,通常传NULL。注意
(1)、线程中,禁止使用exit函数,会导致进程内所有线程全部退出。(2)、pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
4、pthread_join()函数
作用
线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。原形
int pthread_join(pthread_t thread, void **retval);
返回值
成功:0;失败:错误号说明
thread:线程ID (不是指针);retval:存储线程结束状态。
参数retval非空用法
(1)、调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:1、如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
2、如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
3、如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
4、如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。
5、pthread_detach()函数
作用
实现线程分离。原形
int pthread_detach(pthread_t thread);
返回值
成功:0;失败:错误号说明
线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资源仍存于系统中,导致内核认为该进程仍存在。
注意
一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。6、pthread_cancel()函数
作用
杀死(取消)线程。其作用,对应进程中 kill() 函数。原形
int pthread_cancel(pthread_t thread);
返回值
成功:0;失败:错误号注意
(1)、线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write等等。(执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。)
可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用pthreestcancel函数自行设置一个取消点。
(2)、被取消的线程, 退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是-1。可在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join()回收时,得到的返回值为-1。
7、线程使用注意事项
1.主线程退出其他线程不退出,主线程应调用pthread_exit2.避免僵尸线程
①、pthread_join()
②、pthread_detach()
③、pthread_create指定分离属性
被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;
3.malloc和mmap申请的内存可以被其他线程释放
4.应避免在多线程模型中调用fork除非,马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit
5.信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制。
6、在编译链接加 -pthread ,因为线程库属于第三方库,gcc默认加载标准库。
相关文章推荐
- linux线程控制原语1
- Unix线程概念、控制原语、属性
- 线程-线程控制原语
- Unix线程概念、控制原语、属性
- 关于学习进程控制和线程控制的小结
- 信号量线程控制
- 11.4-全栈Java笔记:线程三种状态的控制
- 360度舵机和180度舵机控制方法小结(转)
- Java多线程:用三个线程控制循环输出10次ABC
- vb.net 通过线程来控制界面的方法
- java通过代码控制线程状态,解决线程不安全的问题。
- python学习小结1:for循环控制语句
- 《Java 手机/PDA 程序设计入门》读书笔记8--LCDAUI低级API之 线程 时间控制
- Java多线程、线程的生命周期和状态控制
- java 线程小结
- C# Tip -- 如何优雅的控制线程状态
- C# 中子线程控制进度条的一个简单例子
- 《APUE》笔记-第十二章-线程控制
- 一种简单线程并发控制的实现
- MFC新线程控制进度条