Linux 線程同步的三種方法

http://blog.csdn.net/zsf8701/article/details/7844316

線程的最大特點是資源的共享性,但資源共享中的同步問題是多線程編程的難點。linux下提供了多種方式來處理線程同步,最常用的是互斥鎖、條件變量和信號量。

一、互斥鎖(mutex)

通過鎖機制實現線程間的同步。

  1. 初始化鎖。在Linux下,線程的互斥量數據類型是pthread_mutex_t。在使用前,要對它進行初始化。
    靜態分配:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    動態分配:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
  2. 加鎖。對共享資源的訪問,要對互斥量進行加鎖,如果互斥量已經上了鎖,調用線程會阻塞,直到互斥量被解鎖。
    int pthread_mutex_lock(pthread_mutex *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
  3. 解鎖。在完成了對共享資源的訪問后,要對互斥量進行解鎖。
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
  4. 銷毀鎖。鎖在是使用完成后,需要進行銷毀以釋放資源。
    int pthread_mutex_destroy(pthread_mutex *mutex);
[csharp]?view plaincopy
  1. #include?<cstdio>??
  2. #include?<cstdlib>??
  3. #include?<unistd.h>??
  4. #include?<pthread.h>??
  5. #include?"iostream"??
  6. using?namespace?std;??
  7. pthread_mutex_t?mutex?=?PTHREAD_MUTEX_INITIALIZER;??
  8. int?tmp;??
  9. void*?thread(void?*arg)??
  10. {??
  11. ????cout?<<?"thread?id?is?"?<<?pthread_self()?<<?endl;??
  12. ????pthread_mutex_lock(&mutex);??
  13. ????tmp?=?12;??
  14. ????cout?<<?"Now?a?is?"?<<?tmp?<<?endl;??
  15. ????pthread_mutex_unlock(&mutex);??
  16. ????return?NULL;??
  17. }??
  18. int?main()??
  19. {??
  20. ????pthread_t?id;??
  21. ????cout?<<?"main?thread?id?is?"?<<?pthread_self()?<<?endl;??
  22. ????tmp?=?3;??
  23. ????cout?<<?"In?main?func?tmp?=?"?<<?tmp?<<?endl;??
  24. ????if?(!pthread_create(&id,?NULL,?thread,?NULL))??
  25. ????{??
  26. ????????cout?<<?"Create?thread?success!"?<<?endl;??
  27. ????}??
  28. ????else??
  29. ????{??
  30. ????????cout?<<?"Create?thread?failed!"?<<?endl;??
  31. ????}??
  32. ????pthread_join(id,?NULL);??
  33. ????pthread_mutex_destroy(&mutex);??
  34. ????return?0;??
  35. }??
  36. //編譯:g++?-o?thread?testthread.cpp?-lpthread??

二、條件變量(cond)

互斥鎖不同,條件變量是用來等待而不是用來上鎖的。條件變量用來自動阻塞一個線程,直到某特殊情況發生為止。通常條件變量和互斥鎖同時使用。條件變量分為兩部分: 條件和變量。條件本身是由互斥量保護的。線程在改變條件狀態前先要鎖住互斥量。條件變量使我們可以睡眠等待某種條件出現。條件變量是利用線程間共享的全局變量進行同步的一種機制,主要包括兩個動作:一個線程等待"條件變量的條件成立"而掛起;另一個線程使"條件成立"(給出條件成立信號)。條件的檢測是在互斥鎖的保護下進行的。如果一個條件為假,一個線程自動阻塞,并釋放等待狀態改變的互斥鎖。如果另一個線程改變了條件,它發信號給關聯的條件變量,喚醒一個或多個等待它的線程,重新獲得互斥鎖,重新評價條件。如果兩進程共享可讀寫的內存,條件變量可以被用來實現這兩進程間的線程同步。

  1. 初始化條件變量。
    靜態態初始化,pthread_cond_t cond = PTHREAD_COND_INITIALIER;
    動態初始化,int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
  2. 等待條件成立。釋放鎖,同時阻塞等待條件變量為真才行。timewait()設置等待時間,仍未signal,返回ETIMEOUT(加鎖保證只有一個線程wait)
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
  3. 激活條件變量。pthread_cond_signal,pthread_cond_broadcast(激活所有等待線程)
    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond); //解除所有線程的阻塞
  4. 清除條件變量。無線程等待,否則返回EBUSY
    int pthread_cond_destroy(pthread_cond_t *cond);
[cpp]?view plaincopy
  1. #include?<stdio.h>??
  2. #include?<pthread.h>??
  3. #include?"stdlib.h"??
  4. #include?"unistd.h"??
  5. pthread_mutex_t?mutex;??
  6. pthread_cond_t?cond;??
  7. void?hander(void?*arg)??
  8. {??
  9. ????free(arg);??
  10. ????(void)pthread_mutex_unlock(&mutex);??
  11. }??
  12. void?*thread1(void?*arg)??
  13. {??
  14. ????pthread_cleanup_push(hander,?&mutex);??
  15. ????while(1)??
  16. ????{??
  17. ????????printf("thread1?is?running\n");??
  18. ????????pthread_mutex_lock(&mutex);??
  19. ????????pthread_cond_wait(&cond,?&mutex);??
  20. ????????printf("thread1?applied?the?condition\n");??
  21. ????????pthread_mutex_unlock(&mutex);??
  22. ????????sleep(4);??
  23. ????}??
  24. ????pthread_cleanup_pop(0);??
  25. }??
  26. void?*thread2(void?*arg)??
  27. {??
  28. ????while(1)??
  29. ????{??
  30. ????????printf("thread2?is?running\n");??
  31. ????????pthread_mutex_lock(&mutex);??
  32. ????????pthread_cond_wait(&cond,?&mutex);??
  33. ????????printf("thread2?applied?the?condition\n");??
  34. ????????pthread_mutex_unlock(&mutex);??
  35. ????????sleep(1);??
  36. ????}??
  37. }??
  38. int?main()??
  39. {??
  40. ????pthread_t?thid1,thid2;??
  41. ????printf("condition?variable?study!\n");??
  42. ????pthread_mutex_init(&mutex,?NULL);??
  43. ????pthread_cond_init(&cond,?NULL);??
  44. ????pthread_create(&thid1,?NULL,?thread1,?NULL);??
  45. ????pthread_create(&thid2,?NULL,?thread2,?NULL);??
  46. ????sleep(1);??
  47. ????do??
  48. ????{??
  49. ????????pthread_cond_signal(&cond);??
  50. ????}while(1);??
  51. ????sleep(20);??
  52. ????pthread_exit(0);??
  53. ????return?0;??
  54. }??
[cpp]?view plaincopy
  1. #include?<pthread.h>??
  2. #include?<unistd.h>??
  3. #include?"stdio.h"??
  4. #include?"stdlib.h"??
  5. static?pthread_mutex_t?mtx?=?PTHREAD_MUTEX_INITIALIZER;??
  6. static?pthread_cond_t?cond?=?PTHREAD_COND_INITIALIZER;??
  7. struct?node??
  8. {??
  9. ????int?n_number;??
  10. ????struct?node?*n_next;??
  11. }*head?=?NULL;??
  12. ??
  13. static?void?cleanup_handler(void?*arg)??
  14. {??
  15. ????printf("Cleanup?handler?of?second?thread./n");??
  16. ????free(arg);??
  17. ????(void)pthread_mutex_unlock(&mtx);??
  18. }??
  19. static?void?*thread_func(void?*arg)??
  20. {??
  21. ????struct?node?*p?=?NULL;??
  22. ????pthread_cleanup_push(cleanup_handler,?p);??
  23. ????while?(1)??
  24. ????{??
  25. ????????//這個mutex主要是用來保證pthread_cond_wait的并發性??
  26. ????????pthread_mutex_lock(&mtx);??
  27. ????????while?(head?==?NULL)??
  28. ????????{??
  29. ????????????//這個while要特別說明一下,單個pthread_cond_wait功能很完善,為何??
  30. ????????????//這里要有一個while?(head?==?NULL)呢?因為pthread_cond_wait里的線??
  31. ????????????//程可能會被意外喚醒,如果這個時候head?!=?NULL,則不是我們想要的情況。??
  32. ????????????//這個時候,應該讓線程繼續進入pthread_cond_wait??
  33. ????????????//?pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,??
  34. ????????????//然后阻塞在等待對列里休眠,直到再次被喚醒(大多數情況下是等待的條件成立??
  35. ????????????//而被喚醒,喚醒后,該進程會先鎖定先pthread_mutex_lock(&mtx);,再讀取資源??
  36. ????????????//用這個流程是比較清楚的??
  37. ????????????pthread_cond_wait(&cond,?&mtx);??
  38. ????????????p?=?head;??
  39. ????????????head?=?head->n_next;??
  40. ????????????printf("Got?%d?from?front?of?queue/n",?p->n_number);??
  41. ????????????free(p);??
  42. ????????}??
  43. ????????pthread_mutex_unlock(&mtx);?//臨界區數據操作完畢,釋放互斥鎖??
  44. ????}??
  45. ????pthread_cleanup_pop(0);??
  46. ????return?0;??
  47. }??
  48. int?main(void)??
  49. {??
  50. ????pthread_t?tid;??
  51. ????int?i;??
  52. ????struct?node?*p;??
  53. ????//子線程會一直等待資源,類似生產者和消費者,但是這里的消費者可以是多個消費者,而??
  54. ????//不僅僅支持普通的單個消費者,這個模型雖然簡單,但是很強大??
  55. ????pthread_create(&tid,?NULL,?thread_func,?NULL);??
  56. ????sleep(1);??
  57. ????for?(i?=?0;?i?<?10;?i++)??
  58. ????{??
  59. ????????p?=?(struct?node*)malloc(sizeof(struct?node));??
  60. ????????p->n_number?=?i;??
  61. ????????pthread_mutex_lock(&mtx);?//需要操作head這個臨界資源,先加鎖,??
  62. ????????p->n_next?=?head;??
  63. ????????head?=?p;??
  64. ????????pthread_cond_signal(&cond);??
  65. ????????pthread_mutex_unlock(&mtx);?//解鎖??
  66. ????????sleep(1);??
  67. ????}??
  68. ????printf("thread?1?wanna?end?the?line.So?cancel?thread?2./n");??
  69. ????//關于pthread_cancel,有一點額外的說明,它是從外部終止子線程,子線程會在最近的取消點,退出??
  70. ????//線程,而在我們的代碼里,最近的取消點肯定就是pthread_cond_wait()了。??
  71. ????pthread_cancel(tid);??
  72. ????pthread_join(tid,?NULL);??
  73. ????printf("All?done?--?exiting/n");??
  74. ????return?0;??
  75. }??

三、信號量(sem)

如同進程一樣,線程也可以通過信號量來實現通信,雖然是輕量級的。信號量函數的名字都以"sem_"打頭。線程使用的基本信號量函數有四個。

  1. 信號量初始化。
    int sem_init (sem_t *sem , int pshared, unsigned int value);
    這是對由sem指定的信號量進行初始化,設置好它的共享選項(linux 只支持為0,即表示它是當前進程的局部信號量),然后給它一個初始值VALUE。
  2. 等待信號量。給信號量減1,然后等待直到信號量的值大于0。
    int sem_wait(sem_t *sem);
  3. 釋放信號量。信號量值加1。并通知其他等待線程。
    int sem_post(sem_t *sem);
  4. 銷毀信號量。我們用完信號量后都它進行清理。歸還占有的一切資源。
    int sem_destroy(sem_t *sem);
[cpp]?view plaincopy
  1. #include?<stdlib.h>??
  2. #include?<stdio.h>??
  3. #include?<unistd.h>??
  4. #include?<pthread.h>??
  5. #include?<semaphore.h>??
  6. #include?<errno.h>??
  7. #define?return_if_fail(p)?if((p)?==?0){printf?("[%s]:func?error!/n",?__func__);return;}??
  8. typedef?struct?_PrivInfo??
  9. {??
  10. ????sem_t?s1;??
  11. ????sem_t?s2;??
  12. ????time_t?end_time;??
  13. }PrivInfo;??
  14. ??
  15. static?void?info_init?(PrivInfo*?thiz);??
  16. static?void?info_destroy?(PrivInfo*?thiz);??
  17. static?void*?pthread_func_1?(PrivInfo*?thiz);??
  18. static?void*?pthread_func_2?(PrivInfo*?thiz);??
  19. ??
  20. int?main?(int?argc,?char**?argv)??
  21. {??
  22. ????pthread_t?pt_1?=?0;??
  23. ????pthread_t?pt_2?=?0;??
  24. ????int?ret?=?0;??
  25. ????PrivInfo*?thiz?=?NULL;??
  26. ????thiz?=?(PrivInfo*?)malloc?(sizeof?(PrivInfo));??
  27. ????if?(thiz?==?NULL)??
  28. ????{??
  29. ????????printf?("[%s]:?Failed?to?malloc?priv./n");??
  30. ????????return?-1;??
  31. ????}??
  32. ????info_init?(thiz);??
  33. ????ret?=?pthread_create?(&pt_1,?NULL,?(void*)pthread_func_1,?thiz);??
  34. ????if?(ret?!=?0)??
  35. ????{??
  36. ????????perror?("pthread_1_create:");??
  37. ????}??
  38. ????ret?=?pthread_create?(&pt_2,?NULL,?(void*)pthread_func_2,?thiz);??
  39. ????if?(ret?!=?0)??
  40. ????{??
  41. ????????perror?("pthread_2_create:");??
  42. ????}??
  43. ????pthread_join?(pt_1,?NULL);??
  44. ????pthread_join?(pt_2,?NULL);??
  45. ????info_destroy?(thiz);??
  46. ????return?0;??
  47. }??
  48. static?void?info_init?(PrivInfo*?thiz)??
  49. {??
  50. ????return_if_fail?(thiz?!=?NULL);??
  51. ????thiz->end_time?=?time(NULL)?+?10;??
  52. ????sem_init?(&thiz->s1,?0,?1);??
  53. ????sem_init?(&thiz->s2,?0,?0);??
  54. ????return;??
  55. }??
  56. static?void?info_destroy?(PrivInfo*?thiz)??
  57. {??
  58. ????return_if_fail?(thiz?!=?NULL);??
  59. ????sem_destroy?(&thiz->s1);??
  60. ????sem_destroy?(&thiz->s2);??
  61. ????free?(thiz);??
  62. ????thiz?=?NULL;??
  63. ????return;??
  64. }??
  65. static?void*?pthread_func_1?(PrivInfo*?thiz)??
  66. {??
  67. ????return_if_fail(thiz?!=?NULL);??
  68. ????while?(time(NULL)?<?thiz->end_time)??
  69. ????{??
  70. ????????sem_wait?(&thiz->s2);??
  71. ????????printf?("pthread1:?pthread1?get?the?lock./n");??
  72. ????????sem_post?(&thiz->s1);??
  73. ????????printf?("pthread1:?pthread1?unlock/n");??
  74. ????????sleep?(1);??
  75. ????}??
  76. ????return;??
  77. }??
  78. static?void*?pthread_func_2?(PrivInfo*?thiz)??
  79. {??
  80. ????return_if_fail?(thiz?!=?NULL);??
  81. ????while?(time?(NULL)?<?thiz->end_time)??
  82. ????{??
  83. ????????sem_wait?(&thiz->s1);??
  84. ????????printf?("pthread2:?pthread2?get?the?unlock./n");??
  85. ????????sem_post?(&thiz->s2);??
  86. ????????printf?("pthread2:?pthread2?unlock./n");??
  87. ????????sleep?(1);??
  88. ????}??
  89. ????return;??
  90. }??

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384218.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384218.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384218.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Elixir特性

iex 退出&#xff1a;Ctrl-C 或Ctrl-G再輸入q 回車。 幫助文檔&#xff1a;h 查看輔函數列表 h IO 查看IO模塊幫助 h IO.puts 查看IO模塊中的puts函數的文檔 編譯和運行&#xff1a;創建一個hello.exs的文件。IO.puts "hello world"    //輸出hello world 使用el…

Elixir基礎

值類型 整數&#xff0c;包括十進制&#xff08;1234&#xff09;、十六進制&#xff08;0xcafe&#xff09;、八進制&#xff08;0o765&#xff09;和二進制&#xff08;0b1010&#xff09; 浮點數 原子&#xff0c;原子是常量&#xff0c;用于表現某些東西的名字&#xff0c;…

C++11新特性之八——函數對象function

http://www.cnblogs.com/yyxt/p/3987717.html 詳細請看《C Primer plus》(第六版中文版) http://www.cnblogs.com/lvpengms/archive/2011/02/21/1960078.html 備注&#xff1a; 函數對象&#xff1a; 盡管函數指針被廣泛用于實現函數回調&#xff0c;但C還提供了一個重要的實現…

分塊思想

今天學習了一個算法&#xff08;這個應該叫做算法吧&#xff1f;&#xff09;叫做分塊&#xff08;和莫隊&#xff0c;但是莫隊還沒有搞懂&#xff0c;搞懂再來寫吧&#xff09; 聽起來很高級&#xff0c;蒟蒻表示瑟瑟發抖。但是學完發現怎么那么像是一種變相的暴力呢。 分塊思…

從零開始學C++之STL(八):函數對象、 函數對象與容器、函數對象與算法

http://blog.csdn.net/jnu_simba/article/details/9500219 一、函數對象 1、函數對象&#xff08;function object&#xff09;也稱為仿函數&#xff08;functor&#xff09; 2、一個行為類似函數的對象&#xff0c;它可以沒有參數&#xff0c;也可以帶有若干參數。 3、任何重載…

樹狀數組初步理解

學習樹狀數組已經兩周了&#xff0c;之前偷懶一直沒有寫&#xff0c;趕緊補上防止自己忘記&#xff08;雖然好像已經忘得差不多了&#xff09;。 作為一種經常處理區間問題的數據結構&#xff0c;它和線段樹、分塊一樣&#xff0c;核心就是將區間分成許多個小區間然后通過對大區…

命名函數

函數體是代碼塊 代碼塊do...end是一種表達式的組織方式。 # ./times.exs下defmodule Times dodef doule(n) don * 2end end 函數調用與模式匹配 代碼如下&#xff1a; # ./factorial.exs    計算階層 defmodule Factorial dodef of(0), do: 1          #終止條件…

STL運用的C++技術(6)——函數對象

http://blog.csdn.net/wuzhekai1985/article/details/6658940?_t_t_t0.20427969420870595 STL是C標準庫的重要組成部分之一&#xff0c;它不僅是一個可復用的組件庫&#xff0c;更是一個包含算法與數據結構的軟件框架&#xff0c;同時也是C泛型編程的很好例子。STL中運用了許多…

列表與遞歸

頭部和尾部 [head | tail ] [1] #head 1 tail [] [head | tail ] [1, 2, 3] #head 1 tail [2, 3] [head | tail ] [] #報錯 創建映射函數 我們可以使用一個函數來處理列表中的各個元素&#xff0c;如此可以接受更加復雜的處理&#xff0c;也可以…

優先隊列小結

不像棧和隊列&#xff0c;雖然STL有較好實現但是我們自己也可以很方便的實現&#xff0c;優先隊列自己實現起來就比較復雜&#xff0c;比較浪費時間&#xff08;而且自己目前也不會233&#xff09;而優先隊列因為其較好的特性經常被使用&#xff0c;因此對它的熟練掌握是做題的…

字典:散列表、散列字典、關鍵字列表、集合與結構體

字典 散列表和散列字典都實現了Dict的行為。Keyword模塊也基本實現了&#xff0c;不同之處在于它支持重復鍵。 Eunm.into可以將一種類型的收集映射轉化成另一種。 defmodule Sum dodef values(dict) dodict |> Dict.values |> Enum.sumend endhd [ one: 1, two: 2, thre…

C++11 學習筆記 lambda表達式

http://blog.csdn.net/fjzpdkf/article/details/50249287 lambda表達式是C11最重要也最常用的一個特性之一。lambda來源于函數式編程的概念&#xff0c;也是現代編程語言的一個特點。 一.函數式編程簡介 定義&#xff1a;簡單說&#xff0c;“函數式編程”是一種“編程范式”。…

Cutting Codeforces Round #493 (Div. 2)

Cutting There are a lot of things which could be cut — trees, paper, “the rope”. In this problem you are going to cut a sequence of integers. There is a sequence of integers, which contains the equal number of even and odd numbers. Given a limited bud…

Enum、Stream

Enum 其常見用法見&#xff1a;https://cloud.tencent.com/developer/section/1116852 在sort時&#xff0c;如果要獲得穩定的排序結果&#xff0c;要使用< 而不是 <。 Stream Stream是延遲處理的&#xff0c;而Enum是貪婪的&#xff0c;則意味著傳給它一個收集&#xff…

linux網絡編程之posix 線程(三):posix 匿名信號量與互斥鎖 示例生產者--消費者問題

http://blog.csdn.net/jnu_simba/article/details/9123603 一、posix 信號量 信號量的概念參見這里。前面也講過system v 信號量&#xff0c;現在來說說posix 信號量。 system v 信號量只能用于進程間同步&#xff0c;而posix 信號量除了可以進程間同步&#xff0c;還可以線程間…

洛谷P1080-國王游戲-貪心+高精度

P1080-國王游戲 啊啊啊&#xff0c;剛才已經寫了一次了&#xff0c;但是Edge瀏覽器不知道為什么卡住了&#xff0c;難受。 好吧&#xff0c;其實是一道可做題&#xff0c;分析得到的貪心策略就是就是將a * b小的放在前面&#xff08;其他的懶得說了&#xff09;&#xff0c;主要…

字符串與二進制

單引號字符串會被表示成整數值列表。 &#xff1f;c返回字符 c 的整數編碼。下面這個例子用于解析字符列表表示法&#xff0c;該表示法用于表示一個任意的有符號的十進制數據。 defmodule Parse dodef number([ ?- | tail ]) do_number_digits(tail, 0) * -1enddef number([ ?…

P1092蟲食算-深度優先搜索+玄學剪枝

P1092蟲食算 這道題的思想并不復雜&#xff0c;可是難點在于各種玄學剪枝。在仔細研究了題解大佬的剪枝原理后終于氵了過去。 先上代碼&#xff1a; #include<cstdio> #include<cstring> #include<algorithm> using namespace std;const int MAXN100; int n…

多進程

使用spawn創建一個新進程&#xff0c;其第一個參數是模塊名、第二個參數是函數名、第三個參數是參數列表。spawn會返回一個進程標識符&#xff0c;通常叫做PID。 defmodule Spawn1 dodef greet doreceive do{sender, msg} ->send sender, { :ok, "Hello #{msg}" }…

Linux socket編程(二) 服務器與客戶端的通信

http://www.cnblogs.com/-Lei/archive/2012/09/04/2670964.html上一篇寫了對套接字操作的封裝&#xff0c;這一節使用已封裝好的Socket類實現服務器與客戶端的通信&#xff08;Socket的定義見上篇Socket.h) 服務器端&#xff1a; ServerSocket.h #ifndef SERVERSOCKET_H #defin…