1.線程建立與使用
? ? ? ? ? 創(chuàng)建線程
? ? ? ? ? 初始線程
? ? ? ? ? 線程分離
2.線程生命周期
? ? ? ? ? 就緒態(tài)
? ? ? ? ? 被阻塞
? ? ? ? ? 線程終止
? ? ? ? ?線程回收
1.線程建立與使用
創(chuàng)建線程
1,通過pthread_create()函數(shù)創(chuàng)建線程;
? ? ?1)向該函數(shù)傳遞線程函數(shù)地址和線程函數(shù)參數(shù);
? ? 2 )線程函數(shù)只有一個(gè)void*參數(shù);
? ? ?3)該函數(shù)返回pthread_t類型的線程ID;
2,一般調(diào)用該函數(shù)創(chuàng)建線程,然后調(diào)用pthread_join()函數(shù)等待線程結(jié)束;
3,在當(dāng)前線程從函數(shù)pthread_create()中返回以及新線程被調(diào)度執(zhí)行之間不存在同步關(guān)系;
? ? ?1)新線程可能在當(dāng)前線程從pthread_create()返回值前就運(yùn)行了;
? ? ?2)或在當(dāng)前線程從pthread_create()返回之前,新線程就可能已經(jīng)運(yùn)行完畢了;
pthread_join()
? ? ? ? ? 阻塞其調(diào)用者直到指定線程終止,然后可以選擇地保存線程的返回值;
? ? ? ? ? 當(dāng)pthread_join()調(diào)用返回時(shí),被連接線程就已經(jīng)被分離(detached),再也不能連接該線程了;
? ? ? ? ? 如果連接(joining)線程不關(guān)心返回值,或者它知道被連接(joined)的線程根本不返回任何值,則可向pthread_join()的&retval參數(shù)傳遞NULL,此時(shí),被連接線程的返回值將被忽略;
如何使用可參考pthread_create()、pthread_join()手冊(cè);
初始線程
? ? ? ? C程序運(yùn)行時(shí),首先運(yùn)行main()函數(shù),main()函數(shù)所在線程稱為初始線程或主線程;
? ? ? ? 初始線程可調(diào)用pthread_self()獲得其ID,也可調(diào)用pthread_exit()來終止自己;
? ? ? ? ? ? ? ? ? ? ?從main()返回將導(dǎo)致進(jìn)程終止,也將使進(jìn)程內(nèi)所用線程終止;
? ? ? ? ? ? ? ? ? ? ?在main()中調(diào)用pthread_exit(),這樣進(jìn)程就必須等待所有線程結(jié)束后才能終止;
? ? ? ? ? 若初始線程將其ID保存在一個(gè)其他線程可以訪問的空間,則其他線程就可以等待初始線程的終止或者分離初始線程;
線程分離
? ? ? ? ?分離一個(gè)正在運(yùn)行的線程不會(huì)對(duì)線程帶來任何影響,僅僅是通知系統(tǒng)當(dāng)該線程結(jié)束時(shí),其所屬資源可以被回收;
? ? ? ? ?分離線程意味著通知系統(tǒng)不再需要此線程,允許系統(tǒng)將分配給它的資源回收;
? ? ? ? ? 一個(gè)沒有被分離的線程終止時(shí)會(huì)保留其虛擬內(nèi)存,包括堆棧和其他系統(tǒng)資源。
2.線程生命周期
在任意時(shí)刻,線程處于下表的四個(gè)基本狀態(tài)之一。

線程狀態(tài)轉(zhuǎn)換如下圖。

說明
? ? ? ? ?線程開始處于就緒狀態(tài);
? ? ? ? ?當(dāng)線程運(yùn)行時(shí),它調(diào)用特定的起始函數(shù);
? ? ? ? ?它可能被其他線程搶占,或者因等待外來事情而阻塞自己;
? ? ? ? ? 最終線程完成工作,或者從起始函數(shù)返回,或者調(diào)用pthread_exit函數(shù),即進(jìn)入終止?fàn)顟B(tài);
? ? ? ? ? 如果線程已被分離,則它立刻被回收重用;否則,線程停留在終止?fàn)顟B(tài)直到被分離或被連接;
就緒態(tài)
? ? ? ? ?線程剛被創(chuàng)建時(shí);
? ? ? ? ?線程被解除阻塞再次可以運(yùn)行時(shí);
? ? ? ? ?運(yùn)行線程被搶占時(shí),如時(shí)間片到;
被阻塞
? ? ? ? ?試圖加鎖一個(gè)已經(jīng)被鎖住的互斥量;
? ? ? ? ?等待某個(gè)條件變量;
? ? ? ? ?調(diào)用singwait等待信號(hào);
? ? ? ? ?執(zhí)行無法立即完成的IO操作;
? ? ? ? ?內(nèi)存頁錯(cuò)誤之類的系統(tǒng)操作;
初始線程(main()函數(shù)所在線程)與普通線程區(qū)別
? ? ? ? 1)初始線程的啟動(dòng)函數(shù)main()是從程序外部調(diào)用的;如crt0.o文件復(fù)制初始化進(jìn)程并調(diào)用main()函數(shù);而普通線程的啟動(dòng)函數(shù)及其運(yùn)行參數(shù)均由pthread_create()函數(shù)創(chuàng)建線程時(shí)傳入,且由CPU調(diào)度的;
? ? ? ? ?2)main()函數(shù)的參數(shù)是argc和argv;普通線程的參數(shù)是void*,且由pthread_create()函數(shù)傳入;
? ? ? ? ?3)若普通線程從啟動(dòng)函數(shù)中返回,則線程終止,而其他線程依然可以運(yùn)行;但初始線程從main()返回時(shí),進(jìn)程終止,進(jìn)程內(nèi)所有線程也被終止;
? ? ? ? ? ? ? ? ? ? ? ? ?若希望在初始線程終止時(shí),進(jìn)程中的其他線程繼續(xù)執(zhí)行,則需要在初始線程調(diào)中調(diào)用pthread_exit()而非從main()返回;
? ? ? ? ? 4)大多數(shù)系統(tǒng),初始線程運(yùn)行在默認(rèn)進(jìn)程堆棧上,該堆??梢栽鲩L(zhǎng)到足夠尺寸;而某些實(shí)現(xiàn)中,普通線程的堆??臻g是受限的;
? ? ? ? ? ? ? ? ? ? ? ? ?如果線程堆棧溢出,則程序會(huì)出現(xiàn)段錯(cuò)誤;
線程睡眠原因
? ? ? ? ?被阻塞,需要的某個(gè)資源不可用;
? ? ? ? ?被搶占,即系統(tǒng)將處理器分配給其他線程;
pthread_join()的詳細(xì)解釋
? ? ? ?用來等待一個(gè)線程的結(jié)束;
? ? ? ? ? ? ? ? ? 是一個(gè)線程阻塞函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止;
? ? ? ? ? ? ? ? ? 如,主線程調(diào)用pthread_join()等待它創(chuàng)建的線程運(yùn)行結(jié)束,即主線程調(diào)用該函數(shù)后會(huì)被阻塞;
? ? ? ? ? ? ? ? ? 當(dāng)函數(shù)返回時(shí),被等待的線程的資源被回收;
? ? ? ? ?若此時(shí)新線程沒有運(yùn)行,則它將在主線程被阻塞后從就緒態(tài)進(jìn)入運(yùn)行態(tài);當(dāng)新線程運(yùn)行完畢并返回時(shí),主線程才會(huì)被解除阻塞,返回就緒態(tài);當(dāng)處理器可用時(shí),主線程或立即執(zhí)行或等到創(chuàng)建的線程終止后重新運(yùn)行直到結(jié)束;
線程終止
? ? ? ? 一般地,線程從啟動(dòng)函數(shù)返回來終止自己;
? ? ? ? ?當(dāng)調(diào)用pthread_exit()退出線程或者調(diào)用pthread_cancel()取消線程時(shí),線程在調(diào)用每個(gè)清理過程后也進(jìn)入終止?fàn)顟B(tài);
? ? ? ? ?清理過程又線程通過pthread_cleanup_push()注冊(cè),且尚未通過pthread_cleanup_poo()刪除;
Linux系統(tǒng)僵尸線程
? ? ? ? ?如果線程已經(jīng)被分離,則會(huì)被回收;否則,線程處于終止?fàn)顟B(tài),仍然可以被其他線程調(diào)用pthread_join()連接;
? ? ? ? ?這種線程被稱為僵尸線程,像Unix系統(tǒng)中的進(jìn)程已經(jīng)結(jié)束但還沒有被一個(gè)wait/waitpid調(diào)用回收一樣,即使已經(jīng)死了但還存在;
? ? ? ? ?僵尸線程可能會(huì)保留其運(yùn)行時(shí)的大部分甚至所有資源,因此不應(yīng)該讓線程長(zhǎng)時(shí)間處于這種狀態(tài);當(dāng)創(chuàng)建不需要連接的線程時(shí),應(yīng)該使用detachstate屬性建立線程使其自動(dòng)分離;
線程回收
? ? ? ? ?如果使用detachstate屬性(即設(shè)置屬性為PTHREAD_CREATE_DETACH)建立線程,或者調(diào)用pthread_detach()分離線程,則當(dāng)線程結(jié)束時(shí)將被立刻回收;
? ? ? ? ?如果終止線程沒有被分離,則它將一直處于終止?fàn)顟B(tài)直到被分離(通過pthread_detach)或者被連接(通過pthread_join);
? ? ? ? ?線程一旦被分離,就不能再訪問它;
? ? ? ? ?回收將釋放所有在線程終止時(shí)未釋放的系統(tǒng)和進(jìn)程資源,包括
? ? ? ? ? ? ? ? ? ? ? ?保存線程返回值的內(nèi)存空間、堆棧;
? ? ? ? ? ? ? ? ? ? ? ? 保存寄存器狀態(tài)的內(nèi)存空間;
? ? ? ? ? ? ? ? ? ? ? ? 實(shí)際上線程終止時(shí)上述資源就不能被訪問了;
? ? ? ? ? ?一旦線程被回收,線程ID就無效了,不能再連接、取消或者執(zhí)行其他任何操作;
? ? ? ? ? ?終止線程ID可能被分給新線程;