POSIX多线程—线程基本概念

作者: 评评分分 | 来源:发表于2015-10-18 09:16 被阅读120次

    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可能被分给新线程;


    相关文章

      网友评论

        本文标题:POSIX多线程—线程基本概念

        本文链接:https://www.haomeiwen.com/subject/xcuacttx.html