歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> POSIX---linux多線程編程基礎總結

POSIX---linux多線程編程基礎總結

日期:2017/3/1 11:47:02   编辑:關於Linux

過年不回家了,一直在工作的地方呆著,就騰出了很多時間來學習了。前幾天騰訊給打電話,問了linux下的一些知識,但是答得很不好。自我分析了一下,總結如下:

1.知識學習一遍是遠遠不夠的。還是要多學習,多揣摩,多思考。

2.知識是要經常回頭復習的。

3.程序的工作是要多自己寫代碼實踐,多思考。寫出自己的東西。

好,開始學習linux了。

《線程》,對於一個程序員,如果不懂得線程,那麼我覺得他對基礎的高級程序還是沒有入門的。

線程裡有幾個概念,包括創建,終止,同步,調度,進程交互等概念。

線程並不維持線程表,而是由一個進程維護。

一個進程裡的多個線程共享進程的地址空間。

共享以下:

Process instructions

大多數數據

打開的描述符

信號和信號句柄

當前的工作目錄

用戶和組ID.

但是每個線程唯一擁有的是

線程id,

寄存器集合和棧指針

局部變量的棧內存和返回地址

信號。優先級

返回值。

下面主要貼一下那幾個主要函數吧。

pthreat_t 線程變量

1.創建缺省線程

intpthread_create(pthread_t *tid,cons、劈劈啪啪劈劈啪啪破婆婆tpthread_attr_t *tattr,

void*(*start_routine)(void *), void *arg);

參數:

當pthread_create() 成功時,所創建線程的ID 被存儲在由tid指向的位置中。第二個參數用於設置線程屬性,如果不需要特殊的屬性,可以簡單的設置該參數為NULL,最後兩個參數告訴線程將要啟動執行的函數和傳遞給該函數的參數。

返回值:

調用成功完成後返回0,其他的值都表示出現錯誤。

如果檢測到以下任一情況,pthread_create() 將失敗並返回相應的值。

EAGAIN 超出了系統限制,如創建的線程太多。

EPERM 調用者沒有適當的權限設置所需的參數或安排調度策略

EINVAL 描述:tattr的值無效。(設置的屬性有問題)

默認屬性:綁定,非分離,繼承創建者線程中定義的調度策略。

2.終止線程

voidpthread_exit(void *status);

本函數可用來終止調用線程。將釋放調用線程所有特定數據綁定。如果調用線程尚未分離,則線程ID 和status指定的退出狀態將保持不變,直到應用程序調用pthread_join()以等待該線程。否則,將忽略status。線程ID 可以立即回收。

有一個重要的特殊情況,即當初始線程(即調用main() 的線程)從main() 調用返回時或調用exit() 時,整個進程及其所有的線程將終止。因此,一定要確保初始線程不會從main()過早地返回,在其它線程調用exit()也會終止整個進程。

請注意,如果主線程僅僅調用了pthread_exit,則僅主線程本身終止。進程及進程內的其他線程將繼續存在。所有線程都已終止時,進程也將終止。

3.等待線程終止

intpthread_join(thread_t tid,void **status);

參數:

參數tid指定要等待的線程ID,指定的線程必須位於當前的進程中,而且不得是分離線程。

當參數status不是NULL 時,status指向某個位置,在pthread_join()成功返回時,將該位置設置為已終止線程的退出狀態。

返回值:

調用成功完成後,pthread_join() 將返回零。其他任何返回值都表示出現了錯誤。如果檢測到以下任一情況,pthread_join() 將失敗並返回相應的值。

ESRCH 描述:沒有找到與給定的線程ID 相對應的線程。

EDEADLK 描述:將出現死鎖,如一個線程等待其本身,或者線程A和線程B 互相等待。

EINVAL 描述:與給定的線程ID 相對應的線程是分離線程。

說明:

如果多個線程等待同一個線程終止,則所有等待線程將一直等到目標線程終止。然後,一個等待線程成功返回。其余的等待線程將失敗並返回ESRCH 錯誤。

pthread_join() 僅適用於非分離的目標線程。如果沒有必要等待特定線程終止之後才進行其他處理,則應當將該線程分離。

pthread_exit和pthread_join進一步說明:(一下主線程是main線程)

1.線程自己運行結束,或者調用pthread_exit()結束,線程都會釋放自己獨有的空間資源。

2.如果線程是非分離的,線程會保留線程id號,直到其他線程通過"joining"這個線程確認其已死亡。join 的結果是joining 線程得到已終止線程的退出狀態,已終止的線程將消失。

3.如果線程是分離的,不需要使用pthread_exit(),線程自己運行結束,就會釋放所有資源(包括線程id號)。

4.子線程最終一定要使用pthread_join()或者設置為分離狀態來結束線程,否則線程的資源不會被完全釋放。(使用取消線程功能也不能完全釋放)

5.主線程運行pthread_exit(),會結束主線程,但不會結束子線程。

6.主線程結束,則整個程序結束,所以主線程最好要使用join等待子線程運行結束。使用join一個線程可以等待多個線程結束。

7.使用join的線程將會阻塞,直到被join的線程結束,join函數返回,但是它對被join的線程運行沒有影響。

8.如果子線程使用exit()則可以結束整個進程

4.分離線程

intpthread_detach(thread_t tid);

函數用於指示應用程序在線程tid終止時回收其存儲空間。如果tid尚未終

止,pthread_detach() 不會終止該線程。

返回值:

pthread_detach()在調用成功完成之後返回零。其他任何返回值都表示出現了錯誤。如果檢測到以下任一情況,pthread_detach() 將失敗並返回相應的值。

EINVAL 描述:tid是分離線程。

ESRCH 描述:tid不是當前進程中有效的未分離的線程。

注意:為了避免線程的資源在線程結束時不能得到正確釋放,從而避免產生潛在的內存洩漏問題,在對待線程結束時,要確保該線程處於detached 狀態,否著就需要調用 pthread_join() 函數來對其進行資源回收。(如果不進行以上操作,線程id號不會被回收)。但是如果主線程結束,整個程序就結束了,所以最好在主線程使用,join等待其它線程結束。

5.獲取線程標識符

pthread_tpthread_self(void);

返回調用線程的標識符,(是一個無符號整形數)

6.比較線程ID

intpthread_equal(pthread_t tid1,pthread_t tid2);

如果tid1 和tid2 相等,pthread_equal() 將返回非零值,否則將返回零。如果tid1 或tid2 是無效的線程標識號,則結果無法預測。

7.一次性初始化

intpthread_once(pthread_once_t*once_control, void (*init_routine) (void))

本函數使用初值為PTHREAD_ONCE_INIT的once_control變量保證init_routine()函數在本進程執行序列中僅執行一次。

8簡單例子

view plaincopy
  1. #include
  2. #include
  3. #include
  4. void*print_message_function(void*);
  5. intmain()
  6. {
  7. pthread_tthread1,thread2;
  8. char*mess1="thread1:thisisfirstthread1!!";
  9. char*mess2="thread2:thisissecondthread2!!";
  10. intpth1,pth2;
  11. pth1=pthread_create(&thread1,NULL,print_message_function,(void*)mess1);
  12. pth2=pthread_create(&thread2,NULL,print_message_function,(void*)mess2);
  13. pthread_join(thread1,NULL);
  14. pthread_join(thread2,NULL);
  15. printf("-----------------------------\n");
  16. printf("Thread1returns:%d\n",pth1);
  17. printf("-----------------------------\n");
  18. printf("Thread2returns:%d\n",pth2);
  19. exit(0);
  20. }
  21. void*print_message_function(void*v_message)
  22. {
  23. char*message;
  24. message=(char*)v_message;
  25. printf("haha~%s\n",message);
  26. }

Compile:

C compiler:cc -lpthread pthread1.c
orC++ compiler:g++ -lpthread pthread1.c


Run:./a.out
Results:

Thread 1
Thread 2
Thread 1 returns: 0
Thread 2 returns: 0

線程同步

初始化互斥鎖

1.動態初始化:

intpthread_mutex_init(pthread_mutex_t *mp,

constpthread_mutexattr_t *mattr);

第一個參數指向互斥鎖,第二個參數指向互斥鎖的屬性對象,將mattr設置為NULL的效果與傳遞缺省互斥鎖屬性對象的地址相同,但是沒有內存開銷。

2.靜態初始化:

使用PTHREAD_MUTEX_INITIALIZER 宏可以將以靜態方式定義的互斥鎖初始化為其缺省屬性。

返回值

在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗並返回對應的值。

EBUSY 描述:該實現已檢測到系統嘗試重新初始化mp所引用的對象,即以前進行過初始化但尚未銷毀的互斥鎖。

EINVAL 描述:mattr屬性值無效。互斥鎖尚未修改。

EFAULT 描述:mp所指向的互斥鎖的地址無效。

注意:如果針對以前初始化的互斥鎖調用pthread_mutex_init(),則該互斥鎖還會被重新初始化。

18.銷毀互斥鎖

intpthread_mutex_destroy(pthread_mutex_t *mp);

此函數沒意義,執行之後對鎖沒有影響,可以不用。

初始化互斥鎖

1.動態初始化:

intpthread_mutex_init(pthread_mutex_t *mp,

constpthread_mutexattr_t *mattr);

第一個參數指向互斥鎖,第二個參數指向互斥鎖的屬性對象,將mattr設置為NULL的效果與傳遞缺省互斥鎖屬性對象的地址相同,但是沒有內存開銷。

2.靜態初始化:

使用PTHREAD_MUTEX_INITIALIZER 宏可以將以靜態方式定義的互斥鎖初始化為其缺省屬性。

返回值

在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗並返回對應的值。

EBUSY 描述:該實現已檢測到系統嘗試重新初始化mp所引用的對象,即以前進行過初始化但尚未銷毀的互斥鎖。

EINVAL 描述:mattr屬性值無效。互斥鎖尚未修改。

EFAULT 描述:mp所指向的互斥鎖的地址無效。

注意:如果針對以前初始化的互斥鎖調用pthread_mutex_init(),則該互斥鎖還會被重新初始化。

19.鎖定互斥鎖

intpthread_mutex_lock(pthread_mutex_t *mutex);

當pthread_mutex_lock() 返回時,該互斥鎖已被鎖定。調用線程是該互斥鎖的屬主。如果該互斥鎖已被另一個線程鎖定和擁有,則調用線程將阻塞,直到該互斥鎖變為可用為止。

返回值:

在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下任一情況,該函數將失敗並返回對應的值。

EAGAIN 描述:由於已超出了互斥鎖遞歸鎖定的最大次數,因此無法獲取該互斥鎖。

EDEADLK 描述:當前線程已經擁有互斥鎖

20.解除鎖定互斥鎖

intpthread_mutex_unlock(pthread_mutex_t *mutex);

可釋放mutex引用的互斥鎖對象。互斥鎖的釋放方式取決於互斥鎖的類型屬性。如果調用pthread_mutex_unlock() 時有多個線程被mutex對象阻塞,則互斥鎖變為可用時調度策略可確定獲取該互斥鎖的線程。對PTHREAD_MUTEX_ERRORCHECK_NP類型的互斥鎖,當計數達到零並且調用線程不再對該互斥鎖進行任何鎖定時,該互斥鎖將變為可用。

返回值

在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗並返回對應的值。

EPERM 描述:當前線程不擁有互斥鎖。
view plaincopy

  1. #include
  2. #include
  3. #include
  4. pthread_mutex_tmutex1=PTHREAD_MUTEX_INITIALIZER;
  5. intcounter=0;
  6. void*functionC();
  7. intmain()
  8. {
  9. intpth1,pth2;
  10. pthread_tpthread1,pthread2;
  11. pth1=pthread_create(&pthread1,NULL,functionC,NULL);
  12. pth2=pthread_create(&pthread2,NULL,functionC,NULL);
  13. pthread_join(pthread1,NULL);
  14. pthread_join(pthread2,NULL);
  15. return0;
  16. }
  17. void*functionC()
  18. {
  19. pthread_mutex_lock(&mutex1);
  20. counter++;
  21. printf("Countervalue:%d\n",counter);
  22. pthread_mutex_unlock(&mutex1);
  23. }

29.初始化條件變量

動態方式:intpthread_cond_init(pthread_cond_t *cv,

constpthread_condattr_t *cattr);

靜態方式:使用PTHREAD_COND_INITIALIZER 宏可以將以靜態方式定義的條件變量初始化為其缺省屬性。PTHREAD_COND_INITIALIZER 宏與動態分配具有null屬性的pthread_cond_init()等效,但是不進行錯誤檢查。

pthread_cond_init()在成功完成之後會返回零。

30.基於條件變量阻塞

intpthread_cond_wait(pthread_cond_t *cv,pthread_mutex_t*mutex);

阻塞的線程可以通過pthread_cond_signal() 或pthread_cond_broadcast()喚醒,也可以在信號傳送將其中斷時喚醒。

不能通過pthread_cond_wait() 的返回值來推斷與條件變量相關聯的條件的值的任何變化。必須重新評估此類條件。

pthread_cond_wait()例程每次返回結果時調用線程都會鎖定並且擁有互斥鎖,即使返回錯誤時也是如此。

該條件獲得信號之前,該函數一直被阻塞。該函數會在被阻塞之前以原子方式釋放相關的互斥鎖,並在返回之前以原子方式再次獲取該互斥鎖。

通常,對條件表達式的評估是在互斥鎖的保護下進行的。如果條件表達式為假,線程會基於條件變量阻塞。然後,當該線程更改條件值時,另一個線程會針對條件變量發出信號。這種變化會導致所有等待該條件的線程解除阻塞並嘗試再次獲取互斥鎖。必須重新測試導致等待的條件,然後才能從pthread_cond_wait() 處繼續執行。喚醒的線程重新獲取互斥鎖並從pthread_cond_wait()返回之前,條件可能會發生變化。等待線程可能並未真正喚醒。建議使用的測試方法是,將條件檢查編寫為調用pthread_cond_wait() 的while() 循環。

31.解除阻塞一個線程

intpthread_cond_signal(pthread_cond_t *cv);

應在互斥鎖的保護下修改相關條件,該互斥鎖用於獲得信號的條件變量中。否則,可能在條件變量的測試和pthread_cond_wait() 阻塞之間修改該變量,這會導致無限期等待。

默認設置下還是喚醒第一次被加入的線程,如果沒有任何線程基於條件變量阻塞,則調用pthread_cond_signal() 不起作用。

31.解除阻塞所有線程

intpthread_cond_broadcast(pthread_cond_t *cv);

例子:

view plaincopy
  1. #include
  2. #include
  3. #include
  4. pthread_mutex_tcond_mutex=PTHREAD_MUTEX_INITIALIZER;
  5. pthread_cond_tcond_var=PTHREAD_COND_INITIALIZER;
  6. void*function_cond1();
  7. void*function_cond2();
  8. intcount=0;
  9. #defineCOUNT_DONE10
  10. #defineCOUNT_HALT13
  11. #defineCOUNT_HALT26
  12. intmain()
  13. {
  14. pthread_tthread1,thread2;
  15. pthread_create(&thread1,NULL,function_cond1,NULL);
  16. pthread_create(&thread2,NULL,function_cond2,NULL);
  17. pthread_join(thread1,NULL);
  18. pthread_join(thread2,NULL);
  19. printf("Finalcount:%d\n",count);
  20. return0;
  21. }
  22. void*function_cond1()
  23. {
  24. for(;;)
  25. {
  26. pthread_mutex_lock(&cond_mutex);
  27. pthread_cond_wait(&cond_var,&cond_mutex);
  28. count++;
  29. printf("CountervaluefunctionCount1:%d\n",count);
  30. pthread_mutex_unlock(&cond_mutex);
  31. if(count>=COUNT_DONE)return;
  32. }
  33. }
  34. void*function_cond2()
  35. {
  36. for(;;)
  37. {
  38. pthread_mutex_lock(&cond_mutex);
  39. if(countCOUNT_HALT2)
  40. {
  41. //Conditionofifstatementhasbeenmet.
  42. //Signaltofreewaitingthreadbyfreeingthemutex.
  43. //Note:functionCount1()isnowpermittedtomodify"count".
  44. pthread_cond_signal(&cond_var);
  45. }
  46. else
  47. {
  48. count++;
  49. printf("CountervaluefunctionCount2:%d\n",count);
  50. }
  51. pthread_mutex_unlock(&cond_mutex);
  52. if(count>=COUNT_DONE)return;
  53. }
  54. }

輸出結果:

Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount2: 5
Counter value functionCount2: 6
Counter value functionCount2: 7
Counter value functionCount1: 8
Counter value functionCount1: 9
Counter value functionCount1: 10
Final count: 10


Copyright © Linux教程網 All Rights Reserved