線程創建與終止(Linux_C++)


線程的創建及終止

線程 ID

線程 ID 只在它所屬的進程環境有效,並用 pthread_t 數據類型來表示,實現的時候可以用一個結構來代表 pthread_t 數據類型,所以在可移植的操作系統實現不能把它當做為整數來處理。因此必須使用函數(pthread_equal)來對兩個線程 ID 進行比較。可以用 pthread_self 獲取自身線程 ID 。  

線程的創建

線程創建時並不能保證哪個線程先運行 :  是新創建的線程還是調用線程。新創建的線程可以訪問進程的地址空間,並且繼承調用線程的浮點環境和信號屏蔽字,但是該線程的未決信號集被清除。

errno

注意 pthread 函數在調用失敗時通常會返回錯誤代碼,它們並不像其他的 POSIX 函數一樣設置 errno。每個線程都提供 errno 的副本,這只是為了與使用 errno 的現有函數兼容。在線程中,從函數中返回的錯誤碼更為清晰整潔,不需要依賴那些隨着函數執行不斷變化的全局狀態,因而可以把錯誤的范圍限制在引起出錯的函數中。

線程的終止

如果進程中的任一線程調用了 exit,_Exit,或者_exit,那么整個進程就會終止。於此類似,如果信號的默認動作是終止進程,那么,把該信號發送到線程會終止整個進程。

單個線程終止三種方式

    • 線程只是從啟動例程中返回,返回值是線程的退出碼。
    • 線程可以被同一進程的其他線程取消(線程可以通過 pthread_cancel 函數來請求取消同一進程中的其他線程,默認情況下,pthread_cancel 函數會使得指定的線程的行為表現為如同調用了參數為 PTHREAD_CANCELED 的 pthread_exit 函數。但是線程可以選擇忽略取消方式或是控制取消方式,,pthread_cancel 並不等待線程終止,它僅僅提交請求)。
    • 線程調用 pthread_ext (在 pthread_exit 可以在退出的時候可以傳遞一些信息,那這些信息可以用 pthread_join 函數獲得,那么調用 pthread_join 函數將會一直阻塞,直到指定的線程調用 pthread_exit)。

在默認情況下,線程的終止狀態會保存到該線程調用 pthread_join,如果線程已經處於分離狀態,線程的底層存儲資源可以在線程終止時立即被回收。當線程被分離時,並不能用 pthread_join 函數等待它的終止狀態。對分離狀態的線程進行 pthread_join 的調用可以產生失敗,返回 EINVAL。pthread_detach 調用可以用於使線程進入分離狀態。

資料: 

線程清理處理程序

線程可以安排它退出時需要的函數,這與進程可以用 atexit 函數安排進程退出時需要調用的函數是類似的。這樣的函數稱為線程清理處理程序。線程可以建立多個清理處理程序,處理程序記錄在棧中,也就是說它們的執行順序與它們注冊時的順序相反

    • pthread_cleanup_push(..)  將線程清理處理程序壓棧
    • pthread_cleanup_pop(..)    將線程清理處理程序出棧

 當線程執行以下動作時調用清理函數,調用參數 arg,清理函數 rtn 的調用順序是由 pthread_cleanup_push 函數來安排的。

    • 調用 pthread_exit 時
    • 響應取消請求時
    • 用非零 execute 參數調用 pthread_cleanup_pop 時

如果 execute 參數設置為 0,清理函數將不會被調用。無論哪種情況,pthread_cleanup_pop 都將刪除上次 pthread_clean_push 調用建立的清理處理程序

線程睡眠、阻塞、掛起的區別與解釋

首先這些術語都是對於線程來說的。對線程的控制就好比你控制了一個雇工為你干活。你對雇工的控制是通過編程來實現的。

    • 掛起線程的意思就是你對主動對雇工說:“你睡覺去吧,用着你的時候我主動去叫你,然后接着干活”。
    • 線程睡眠的意思就是你主動對雇工說:“你睡覺去吧,某時某刻過來報到,然后接着干活”。
    • 線程阻塞的意思就是,你突然發現,你的雇工不知道在什么時候沒經過你允許,自己睡覺呢,但是你不能怪雇工,肯定你這個雇主沒注意,本來你讓雇工掃地,結果掃帚被偷了或被鄰居家借去了,你又沒讓雇工繼續干別的活,他就只好睡覺了。至於掃帚回來后,雇工會不會知道,會不會繼續干活,你不用擔心,雇工一旦發現掃帚回來了,他就會自己去干活的。因為雇工受過良好的培訓。這個培訓機構就是操作系統。

例子:

線程的創建以及等待其終止

#include<iostream>
#include<pthread.h>
#include<unistd.h>

using namespace std;

void *th_fn(void *arg)
{
    cout<<"new thread"<<endl;
    return (void *)10;
}

int main()
{
    pthread_t ptid;
    void *tret;

    pthread_create(&ptid, NULL,th_fn ,NULL);

    pthread_join(ptid, &tret);
    cout<<"code 2 exit id = "<<(int)tret<<endl;
    
    return 0;
}
View Code

運行結果:

 


線程的屬性與限制

線程限制

線程的限制可以通過 sysconf 函數來進行查詢。

    • PTHREAD_DESTRUCTOR_ITERATIONS    線程退出時,操作系統實現試圖銷毀線程私有數據的最大次數。
    • PTHREAD_KEYS_MAX                                進程可以創建的鍵的最大數目
    • PTHREAD_STACK_MIN                               一個線程的棧可用的最小字節數
    • PTHREAD_THREADS_MAX                         進程可以創建的最大線程數

線程的屬性

初始化線程屬性/銷毀線程屬性

    • pthread_attr_init(..)
    • pthread_attr_destroy(..)

如果要去除對  pthread_attr_t 結構的初始化,可以調用 pthread_attr_destroy 函數。如果 pthread_attr_init 實現時為屬性對象分配了動態內存空間,pthread_attr_destroy 將會釋放內存空間。除此之外, pthread_attr_destroy 還會用無效的值初始化屬性對象,因此如果該屬性對象被誤用,將會導致 pthread_create 函數返回錯誤。

    • detachstate(..)   線程的分離狀態屬性(如果對現有的某個線程的終止狀態不感興趣的話,可以使用 pthread_detach 函數讓操作系統在線程退出時收回它所占用的資源)
    • guardsize(..)    線程棧末尾的警戒緩沖區大小
    • stackaddr(..)    線程棧的最低地址
    • stacksize(..)    線程棧的大小

設置和獲得線程的分離屬性

    • pthread_attr_getdetachstate(..)
    • pthread_attr_setdetachstate(..)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM