1. 程式人生 > >Linux—POSIX多執行緒管理-詳解

Linux—POSIX多執行緒管理-詳解

還在編寫中.....

多執行緒開發在 Linux 平臺上已經有成熟的 Pthread 庫支援。其涉及的多執行緒開發的最基本概念主要包含三點:執行緒,互斥鎖,條件。其中,執行緒操作又分執行緒的建立,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是建立,銷燬,加鎖和解鎖。條件操作有 5 種操作:建立,銷燬,觸發,廣播和等待。其他的一些執行緒擴充套件概念,如訊號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。


互斥鎖是多執行緒程式設計中基本的概念,在開發中被廣泛使用。其呼叫次序層次清晰簡單:建鎖,加鎖,解鎖,銷燬鎖。但是需要注意的是,與諸如 Windows 平臺的互斥變數不同,在預設情況下,Linux 下的同一執行緒無法對同一互斥鎖進行遞迴加速,否則將發生

死鎖

1、所謂遞迴加鎖,就是在同一執行緒中試圖對互斥鎖進行兩次或兩次以上的行為。

這個問題與互斥鎖的中的預設 recursive 屬性有關。解決問題的方法就是顯式地在互斥變數初始化時將設定起 recursive 屬性。基於此,以上程式碼其實稍作修改就可以很好的執行,只需要在初始化鎖的時候加設定一個屬性。因此,建議儘量設定 recursive 屬性以初始化 Linux 的互斥鎖,這樣既可以解決同一執行緒遞迴加鎖的問題,又可以避免很多情況下死鎖的發生。這樣做還有一個額外的好處,就是可以讓 Windows 和 Linux 下讓鎖的表現統一。

pthread_mutexattr_init(&attr); 
    // 設定 recursive 屬性
    pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP); 
    pthread_mutex_init(theMutex,&attr);
2、等待的絕對時間問題

超時是多執行緒程式設計中一個常見的概念。例如,當你在 Linux 平臺下使用 pthread_cond_timedwait() 時就需要指定超時這個引數,以便這個 API 的呼叫者最多隻被阻塞指定的時間間隔。但是如果你是第一次使用這個 API 時,首先你需要了解的就是這個 API 當中超時引數的特殊性(就如本節標題所提示的那樣)。

函式定義:

int pthread_cond_timedwait(pthread_cond_t *restrict cond, 
              pthread_mutex_t *restrict mutex, 
              const struct timespec *restrict abstime);

引數 abstime 在這裡用來表示和超時時間相關的一個引數,但是需要注意的是它所表示的是一個絕對時間,而不是一個時間間隔數值,只有當系統的當前時間達到或者超過 abstime 所表示的時間時,才會觸發超時事件。這對於擁有 Windows 平臺執行緒開發經驗的人來說可能尤為困惑。因為 Windows 平臺下所有的 API 等待引數(如 SignalObjectAndWait,等)都是相對時間,假設我們指定相對的超時時間引數如 dwMilliseconds (單位毫秒)來呼叫和超時相關的函式,這樣就需要將 dwMilliseconds 轉化為 Linux 下的絕對時間引數 abstime 使用。

3、正確處理Linux平臺下的執行緒結束問題

在 Linux 平臺下,當處理執行緒結束時需要注意的一個問題就是如何讓一個執行緒善始善終,讓其所佔資源得到正確釋放。在 Linux 平臺預設情況下,雖然各個執行緒之間是相互獨立的,一個執行緒的終止不會去通知或影響其他的執行緒。但是已經終止的執行緒的資源並不會隨著執行緒的終止而得到釋放,我們需要呼叫 pthread_join() 來獲得另一個執行緒的終止狀態並且釋放該執行緒所佔的資源。

int pthread_join(pthread_t th, void **thread_return);

呼叫該函式的執行緒將掛起,等待 th 所表示的執行緒的結束。 thread_return 是指向執行緒 th 返回值的指標。需要注意的是 th 所表示的執行緒必須是 joinable 的,即處於非 detached(遊離)狀態;並且只可以有唯一的一個執行緒對 th 呼叫 pthread_join() 。如果 th 處於 detached 狀態,那麼對 th 的 pthread_join() 呼叫將返回錯誤。如果你壓根兒不關心一個執行緒的結束狀態,那麼也可以將一個執行緒設定為 detached 狀態從而來讓作業系統在該執行緒結束時來回收它所佔的資源。在任何一個時間點上,執行緒是可結合的(joinable),或者是分離的(detached)。一個可結合的執行緒能夠被其他執行緒收回其資源和殺死在被其他執行緒回收之前,它的儲存器資源(如棧)是不釋放的。相反,一個分離的執行緒是不能被其他執行緒回收或殺死的,它的儲存器資源在它終止時由系統自動釋放。將一個執行緒設定為 detached 狀態可以通過兩種方式來實現。一種是呼叫 pthread_detach() 函式,可以將執行緒 th 設定為 detached 狀態。另一種方法是在建立執行緒時就將它設定為 detached 狀態,首先初始化一個執行緒屬性變數,然後將其設定為 detached 狀態,最後將它作為引數傳入執行緒建立函式pthread_create(),這樣所創建出來的執行緒就直接處於 detached 狀態。

建立 detach 執行緒:

    pthread_t       tid;

    pthread_attr_t  attr;

    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    pthread_create(&tid, &attr, THREAD_FUNCTION, arg);

總之為了在使用 pthread 時避免執行緒的資源線上程結束時不能得到正確釋放,從而避免產生潛在的記憶體洩漏問題,在對待執行緒結束時,要確保該執行緒處於 detached 狀態,否著就需要呼叫 pthread_join()函式來對其進行資源回收。


Linux核心執行緒之深入淺出  :http://blog.163.com/jiams_wang/blog/static/303391492012103010374038/

Linux多執行緒——使用訊號量同步執行緒:http://blog.csdn.net/ljianhui/article/details/10813469

Linux多執行緒——使用互斥量同步執行緒:http://blog.csdn.net/ljianhui/article/details/10875883

多執行緒程式設計注意事項:http://blog.csdn.net/l_yangliu/article/details/7104845

------------------------------------------------------------------一條華麗的分割線----------------------------------------------------------------------

   argc是命令列總的引數個數 
 argv[]是argc個引數,其中第0個引數是程式的全名,以後的引數 
 命令列後面跟的使用者輸入的引數,比如: 
 int  main(int  argc,  char*  argv[]) 
 { 
 int  i; 
 for  (i  =  0;  i<argc;  i++) 
 cout<<argv[i]<<endl; 
 cin>>i; 
 return  0; 
 } 
 執行時敲入 
 F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE  aaaa  bbb  ccc  ddd 
 輸出如下: 
 F:\MYDOCU~1\TEMPCODE\D1\DEBUG\D1.EXE 
 aaaa 
 bbb 
 ccc 
 ddd 
--------------------------------------------------------------------
char  *argv[]是一個字元陣列,其大小是int  argc,主要用於命令列引數  argv[]  引數,數組裡每個元素代表一個引數;