一. 线程
可以知道,进程是作为系统中资源分配的一个基本实体,而线程就是在进程中作为资源调度的一个基本运行单位。
一个进程当中可以有多个线程,这些线程共享调用它们的进程中的资源,比如进程的uid和gid;比如文件描述符表和当前工作目录;比如每种信号的处理方式等;
但是每个线程也有属于自己私有的一份数据,比如每个线程都有自己的ID号;有自己的上下文,包括各种寄存器的值、程序计数器和栈指针什么的;每个线程也都有自己独立的栈空间;errno变量、信号屏蔽字和调度优先级等。
进程强调的是资源的独占性,而进程则是资源的共享。
======================================================================================================================================================================================
二. 线程控制
下面要谈到的线程是由POSIX标准定义的,称为POSIX thread或pthread,在Linux上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread。
-------------------------------------------------------------------------------------------
创建线程
函数参数中,
thread是一个线程的指针;
attr是一个结构体的指针,通常我们可以设定为NULL,以系统默认方式;
start_routine是一个函数指针,表示线程要执行的代码区;
arg则是在函数中要传递的参数;
函数执行成功返回0,并且会将新创建的线程ID放入thread所指向的内存单元中;若失败返回错误码;
-------------------------------------------------------------------------------------------
2. 终止线程
终止一个线程有三种方式:
函数参数中thread是指要取消线程的ID号,若一个线程要自己取消自己,可通过pthread_self函数来获取自身的ID号:
函数参数为空,返回值为一个线程的ID号;
注意:不能在一个线程中调用exit函数,因为exit函数会终止整个进程,也就是终止进程中的所有线程。
-------------------------------------------------------------------------------------------
3. 等待线程
在进程中,父进程可通过调用wait函数来等待子进程获取其退出状态,同样,在线程中也可以在主线程中调用等待函数来获取其他线程的退出信息:
函数参数中,
thread是要等待的线程ID号;
retval是一个二级指针,用来获取线程的退出值;
若成功返回0,失败返回错误码;
调用该函数的线程将挂起等待直到ID号为thread的线程终止,要等待的线程以不同的方式终止通过pthread_join函数得到的终止状态是不一样的:
如果thread线程通过return终止,那么retval所指向的内存单元存放的就是线程函数的返回值;
如果thread线程被别的线程调用pthread_cancel函数终止掉的,retval所指向的内存单元存放的是常数PTHREAD_CANCELED;
如果thread线程是自己调用pthread_exit函数终止的,那么retval所指向的内存单元存放的是传递给pthread_exit函数的参数;
-------------------------------------------------------------------------------------------
栗子时间:
程序中创建出了三个线程,每个线程运行自己的线程函数,终止线程的方式各不相同,
运行结果如下:
可以看到在结果中,每个线程的ID号都不相同,thread1直接在线程函数内部返回,retval就为返回值;thread2调用pthread_exit函数,retval就为函数参数;thread3调用函数pthread_cancel函数,返回值为0;
上述程序中,如果在主线程内部调用pthread_cancel函数来终止thread3的话,可以得到返回值为-1也就是上面所述的常量PTHREAD_CANCELED。
======================================================================================================================================================================================
三. 线程分离
默认情况下,线程是可结合的,也可以是分离的,一个可结合的线程能够被其他线程终止并回收资源,在被其他线程回收之前,它的存储器资源是不释放的;相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放,也就是说,如果一个线程已经处于分离(detach)状态了,就不可以调用pthread_join函数。
如果一个可结合线程运行结束以后没有被pthread_join函数获取其退出状态,那就类似于进程中的僵尸进程,有一部分资源并没有被完全回收;而如果一个线程调用了pthread_join但要获取的线程还没有运行完毕,那等待的进程就会被挂起阻塞,直到线程运行完成。如若不想线程被挂起阻塞,可以将该线程设置为分离(detach)的,这样一来就没有线程会因等待而被阻塞,也不会有线程的资源没有被回收完的问题了。
将线程设置为分离的函数如下:
函数参数就是要被设置为分离状态的线程ID,成功返回值为0,失败返回错误码;
不能对同一线程两次pthread_join,也不能将一个线程调用pthread_detach分离之后再调用pthread_join;
栗子时间:
运行程序,结果为:
返回值为零,说明函数调用成功;
下面将程序改为将线程detach之后再调用pthread_join函数:
运行程序,的如下结果:
主线程pthread_join失败,可知当一个线程已经被分离之后,再join等待获取其退出状态是无效的。
======================================================================================================================================================================================
四. 总结
进程是系统中分配资源的基本单位,强调资源的独占性;线程是进程中调度资源的基本实体,强调资源的共享,但也有其各自的数据空间;
和进程一样,线程也需要创建并调用自己的运行空间,执行进程中不同的分支流;
线程的退出有三种方式:直接return、调用pthread_exit、调用pthread_cancel函数;
创建出线程也需要有进程等待调用pthread_join函数获取退出状态,若不被获取,就会和僵尸进程一样保持退出状态直至被join;若没有运行结束则调用pthread_join的线程被挂起等待;
一个线程是可结合的也是可分离的,被pthread_detach分离的线程就不能再被其他线程pthread_join获取其退出状态了,一个线程不能被join两次。
《完》
本文出自 “敲完代码好睡觉zzz” 博客,请务必保留此出处http://2627lounuo.blog.51cto.com/10696599/1764792
原文:http://2627lounuo.blog.51cto.com/10696599/1764792