1.线程建立与使用
创建线程
初始线程
线程分离
2.线程生命周期
就绪态
被阻塞
线程终止
线程回收
1.线程建立与使用
创建线程
1,通过pthread_create()函数创建线程;
1)向该函数传递线程函数地址和线程函数参数;
2 )线程函数只有一个void*参数;
3)该函数返回pthread_t类型的线程ID;
2,一般调用该函数创建线程,然后调用pthread_join()函数等待线程结束;
3,在当前线程从函数pthread_create()中返回以及新线程被调度执行之间不存在同步关系;
1)新线程可能在当前线程从pthread_create()返回值前就运行了;
2)或在当前线程从pthread_create()返回之前,新线程就可能已经运行完毕了;
pthread_join()
阻塞其调用者直到指定线程终止,然后可以选择地保存线程的返回值;
当pthread_join()调用返回时,被连接线程就已经被分离(detached),再也不能连接该线程了;
如果连接(joining)线程不关心返回值,或者它知道被连接(joined)的线程根本不返回任何值,则可向pthread_join()的&retval参数传递NULL,此时,被连接线程的返回值将被忽略;
如何使用可参考pthread_create()、pthread_join()手册;
初始线程
C程序运行时,首先运行main()函数,main()函数所在线程称为初始线程或主线程;
初始线程可调用pthread_self()获得其ID,也可调用pthread_exit()来终止自己;
从main()返回将导致进程终止,也将使进程内所用线程终止;
在main()中调用pthread_exit(),这样进程就必须等待所有线程结束后才能终止;
若初始线程将其ID保存在一个其他线程可以访问的空间,则其他线程就可以等待初始线程的终止或者分离初始线程;
线程分离
分离一个正在运行的线程不会对线程带来任何影响,仅仅是通知系统当该线程结束时,其所属资源可以被回收;
分离线程意味着通知系统不再需要此线程,允许系统将分配给它的资源回收;
一个没有被分离的线程终止时会保留其虚拟内存,包括堆栈和其他系统资源。
2.线程生命周期
在任意时刻,线程处于下表的四个基本状态之一。
线程状态转换如下图。
说明
线程开始处于就绪状态;
当线程运行时,它调用特定的起始函数;
它可能被其他线程抢占,或者因等待外来事情而阻塞自己;
最终线程完成工作,或者从起始函数返回,或者调用pthread_exit函数,即进入终止状态;
如果线程已被分离,则它立刻被回收重用;否则,线程停留在终止状态直到被分离或被连接;
就绪态
线程刚被创建时;
线程被解除阻塞再次可以运行时;
运行线程被抢占时,如时间片到;
被阻塞
试图加锁一个已经被锁住的互斥量;
等待某个条件变量;
调用singwait等待信号;
执行无法立即完成的IO操作;
内存页错误之类的系统操作;
初始线程(main()函数所在线程)与普通线程区别
1)初始线程的启动函数main()是从程序外部调用的;如crt0.o文件复制初始化进程并调用main()函数;而普通线程的启动函数及其运行参数均由pthread_create()函数创建线程时传入,且由CPU调度的;
2)main()函数的参数是argc和argv;普通线程的参数是void*,且由pthread_create()函数传入;
3)若普通线程从启动函数中返回,则线程终止,而其他线程依然可以运行;但初始线程从main()返回时,进程终止,进程内所有线程也被终止;
若希望在初始线程终止时,进程中的其他线程继续执行,则需要在初始线程调中调用pthread_exit()而非从main()返回;
4)大多数系统,初始线程运行在默认进程堆栈上,该堆栈可以增长到足够尺寸;而某些实现中,普通线程的堆栈空间是受限的;
如果线程堆栈溢出,则程序会出现段错误;
线程睡眠原因
被阻塞,需要的某个资源不可用;
被抢占,即系统将处理器分配给其他线程;
pthread_join()的详细解释
用来等待一个线程的结束;
是一个线程阻塞函数,调用它的函数将一直等待到被等待的线程结束为止;
如,主线程调用pthread_join()等待它创建的线程运行结束,即主线程调用该函数后会被阻塞;
当函数返回时,被等待的线程的资源被回收;
若此时新线程没有运行,则它将在主线程被阻塞后从就绪态进入运行态;当新线程运行完毕并返回时,主线程才会被解除阻塞,返回就绪态;当处理器可用时,主线程或立即执行或等到创建的线程终止后重新运行直到结束;
线程终止
一般地,线程从启动函数返回来终止自己;
当调用pthread_exit()退出线程或者调用pthread_cancel()取消线程时,线程在调用每个清理过程后也进入终止状态;
清理过程又线程通过pthread_cleanup_push()注册,且尚未通过pthread_cleanup_poo()删除;
Linux系统僵尸线程
如果线程已经被分离,则会被回收;否则,线程处于终止状态,仍然可以被其他线程调用pthread_join()连接;
这种线程被称为僵尸线程,像Unix系统中的进程已经结束但还没有被一个wait/waitpid调用回收一样,即使已经死了但还存在;
僵尸线程可能会保留其运行时的大部分甚至所有资源,因此不应该让线程长时间处于这种状态;当创建不需要连接的线程时,应该使用detachstate属性建立线程使其自动分离;
线程回收
如果使用detachstate属性(即设置属性为PTHREAD_CREATE_DETACH)建立线程,或者调用pthread_detach()分离线程,则当线程结束时将被立刻回收;
如果终止线程没有被分离,则它将一直处于终止状态直到被分离(通过pthread_detach)或者被连接(通过pthread_join);
线程一旦被分离,就不能再访问它;
回收将释放所有在线程终止时未释放的系统和进程资源,包括
保存线程返回值的内存空间、堆栈;
保存寄存器状态的内存空间;
实际上线程终止时上述资源就不能被访问了;
一旦线程被回收,线程ID就无效了,不能再连接、取消或者执行其他任何操作;
终止线程ID可能被分给新线程;