Posix線程 它們那一大家子事兒,要覺得好你就收藏進被窩慢慢看(2)

      網友投稿 690 2025-04-01

      接上一篇 Posix線程(1)

      文章目錄

      ①線程同步

      線程為什么要同步?

      ②互斥鎖

      互斥量原語

      參數釋義

      互斥量使用

      死鎖

      ③條件變量

      條件變量原語

      條件變量與互斥鎖

      注意事項

      虛假喚醒與喚醒丟失

      ⑴虛假喚醒

      ⑵喚醒丟失

      使用條件變量

      ③線程池

      ④Pthread API函數

      ①線程同步

      線程為什么要同步?

      做個小實驗吧,兩個線程計數。如果最后加起來是20萬那就不用往下看了。

      #include #include #include int count = 0;//聲明全局變量,等下就看看它了 void *run(void *arg) { int i = 0; for(i = 0;i < 100000; i++) { count++; printf("Count:%d\n",count); usleep(2); } return (void*)0; } int main(int argc,char **argv) { pthread_t tid1,tid2; int err1,err2; err1 = pthread_create(&tid1,NULL,run,NULL); err2 = pthread_create(&tid2,NULL,run,NULL); if(err1==0 && err2==0)//倆線程都成功創建出來 { pthread_join(tid1,NULL); pthread_join(tid2,NULL); } return 0; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      好,為什么要線程同步,那就心照不宣了

      算了,官方話還是要說一說的

      1、共享資源,多個線程都可以對共享資源進行操作

      2、線程操作共享資源的先后順序不一定

      3、處理器對存儲器的操作一般不是原子操作

      ②互斥鎖

      什么叫互斥量,顧名思義就是咱這么多人,只能有一個使用這個資源,就像共享小單車,一次只能給一個人用,一個人下車鎖車了,另一個人才能去掃碼開鎖。

      互斥量原語

      pthread_mutex_t mutex = PTHREAD_MUREX_INITALIZER //用于初始化互斥鎖,后面簡稱鎖 int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); //初始化鎖,和上面那個一個意思。 //初始化一個互斥鎖(互斥量)–>初值可看做1 int pthread_mutex_destroy(pthread_mutex_t *mutex); //銷毀鎖 int pthread_mutex_lock(pthread_mutex_t *mutex); //上鎖 int pthread_mutex_unlok(pthread_mutex_t *mutex); //解鎖 int pthread_mutex_trylock(pthread_mutex_t *mutex); //嘗試上鎖

      1

      2

      3

      4

      5

      6

      7

      8

      參數釋義

      <這里只釋義那個init>

      參數1:傳出參數,調用時應傳&mutex

      restrict關鍵字:只用于限制指針,告訴編譯器,所有修改該指針指向內存中內容的操作,只能通過本指針完成。不能通過除本指針以外的其他變量或指針修改。

      參數2:互斥屬性。是一個傳入參數,通常傳NULL,選用默認屬性(線程間共享).

      靜態初始化:如果互斥鎖mutex是靜態分配的(定義在全局,或加了static關鍵字修飾),可以直接使用宏進行初始化。pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

      動態初始化:局部變量應采用動態初始化。pthread_mutex_init(&mutex, NULL);

      attr對象用于設置互斥量對象的屬性,使用時必須聲明為pthread_mutextattr_t類型,默認值可以是NULL。Pthreads標準定義了三種可選的互斥量屬性:

      協議(Protocol): 指定了協議用于阻止互斥量的優先級改變

      優先級上限(Prioceiling):指定互斥量的優先級上限

      進程共享(Process-shared):指定進程共享互斥量

      注意所有實現都提供了這三個可選的互斥量屬性。

      Q:有多個線程等待同一個鎖定的互斥量,當互斥量被解鎖后,那個線程會第一個鎖定互斥量? A:除非線程使用了優先級調度機制,否則,線程會被系統調度器去分配,那個線程會第一個鎖定互斥量是隨機的。

      1

      2

      3

      互斥量使用

      #include #include #include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int count = 0; void *run(void *arg) { int i = 0; for(i = 0;i < 100000; i++) { pthread_mutex_lock(&mutex); count++; printf("Count:%d\n",count); usleep(2); pthread_mutex_unlock(&mutex); } return (void*)0; } int main(int argc,char **argv) { pthread_t tid1,tid2; int err1,err2; err1 = pthread_create(&tid1,NULL,run,NULL); err2 = pthread_create(&tid2,NULL,run,NULL); if(err1==0 && err2==0) { pthread_join(tid1,NULL); pthread_join(tid2,NULL); } return 0; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      拿去執行,如果不是20萬也可以不用往下看了。

      死鎖

      為什么我要強調上鎖和解鎖一定要放在一起寫,就是防止出現人為失誤導致死鎖

      死鎖嘛,解不開了。

      要么是你忘了解開,別人也就沒得用了

      要么就是幾個線程互相掐著關鍵數據導致誰也沒辦法完成任務,結果誰也沒辦法解鎖。

      這種情況下只有銷毀掉代價最小的那個鎖,讓任務執行下去,不過后面要記得把那個被銷毀的任務重新運作。

      ③條件變量

      條件變量提供了另一種同步的方式?;コ饬客ㄟ^控制對數據的訪問實現了同步,而條件變量允許根據實際的數據值來實現同步。

      沒有條件變量,程序員就必須使用線程去輪詢(可能在臨界區),查看條件是否滿足。這樣比較消耗資源,因為線程連續繁忙工作。條件變量是一種可以實現這種輪詢的方式。

      條件變量往往和互斥一起使用

      使用條件變量的代表性順序如下:

      條件變量原語

      //初始化條件變量: //本人還是喜歡靜態初始化,省事兒 pthread_cont_t cont = PTHREAD_COND_INITIALIZER; //好,再看看動態初始化 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); //參數釋義:cond:用于接收初始化成功管道條件變量 //attr:通常為NULL,且被忽略 //有初始化那肯定得有銷毀 int pthread_cond_destroy(pthread_cond_t *cond); //既然說條件變量是用來等待的,那就更要看看這等待的特殊之處了 int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); //無條件等待 int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime); //計時等待 //好,加入等待喚醒大軍了,那得看看怎么去喚醒了 int pthread_cond_signal(pthread_cond_t *cptr); //喚醒一個等待該條件的線程。存在多個線程是按照其隊列入隊順序喚醒其中一個 int pthread_cond_broadcast(pthread_cond_t * cptr); //廣播,喚醒所喲與等待線程

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      條件變量與互斥鎖

      在服務器編程中常用的線程池,多個線程會操作同一個任務隊列,一旦發現任務隊列中有新的任務,子線程將取出任務;這里因為是多線程操作,必然會涉及到用互斥鎖保護任務隊列的情況(否則其中一個線程操作了任務隊列,取出線程到一半時,線程切換又取出相同任務)。但是互斥鎖一個明顯的缺點是它只有兩種狀態:鎖定和非鎖定。設想,每個線程為了獲取新的任務不斷得進行這樣的操作:鎖定任務隊列,檢查任務隊列是否有新的任務,取得新的任務(有新的任務)或不做任何操作(無新的任務),釋放鎖,這將是很消耗資源的。

      而條件變量通過允許線程阻塞和等待另一個線程發送信號的方法彌補了互斥鎖的不足,它常和互斥鎖一起配合使用。使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程往往解開相應的互斥鎖并等待條件發生變化。一旦其他的某個線程改變了條件變量,他將通知相應的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測試條件是否滿足。一般說來,條件變量被用來進行線程間的同步。對應于線程池的場景,我們可以讓線程處于等待狀態,當主線程將新的任務放入工作隊列時,發出通知(其中一個或多個),得到通知的線程重新獲得鎖,取得任務,執行相關操作。

      注意事項

      (1)必須在互斥鎖的保護下喚醒,否則喚醒可能發生在鎖定條件變量之前,照成死鎖。

      (2)喚醒阻塞在條件變量上的所有線程的順序由調度策略決定

      (3)如果沒有線程被阻塞在調度隊列上,那么喚醒將沒有作用。

      (4)以前不懂事兒,就喜歡廣播。由于pthread_cond_broadcast函數喚醒所有阻塞在某個條件變量上的線程,這些線程被喚醒后將再次競爭相應的互斥鎖,所以必須小心使用pthread_cond_broadcast函數。

      虛假喚醒與喚醒丟失

      ⑴虛假喚醒

      在多核處理器下,pthread_cond_signal可能會激活多于一個線程(阻塞在條件變量上的線程)。結果是,當一個線程調用pthread_cond_signal()后,多個調用pthread_cond_wait()或pthread_cond_timedwait()的線程返回。這種效應成為”虛假喚醒”(spurious wakeup)

      Linux幫助里面有

      為什么不去修正,性價比不高嘛。

      所以通常的標準解決辦法是這樣的:

      ⑵喚醒丟失

      無論哪種等待方式,都必須和一個互斥量配合,以防止多個線程來打擾。

      互斥鎖必須是普通鎖或適應鎖,并且在進入pthread_cond_wait之前必須由本線程加鎖。

      在更新等待隊列前,mutex必須保持鎖定狀態. 在線程進入掛起,進入等待前,解鎖。(好繞啊,我已經盡力斷句了)

      在條件滿足并離開pthread_cond_wait前,上鎖。以恢復它進入cont_wait之前的狀態。

      為什么等待會被上鎖?

      以免出現喚醒丟失問題。 這里有個大神解釋要不要看:https://stackoverflow.com/questions/4544234/calling-pthread-cond-signal-without-locking-mutex 做事做全套,源碼也給放這兒了:https://code.woboq.org/userspace/glibc/nptl/pthread_cond_wait.c.html

      1

      2

      3

      在放些咱能看懂的中文解釋:將線程加入喚醒隊列后方可解鎖。保證了線程在陷入wait后至被加入喚醒隊列這段時間內是原子的。

      但這種原子性依賴一個前提條件:喚醒者在調用pthread_cond_broadcast或pthread_cond_signal喚醒等待者之前也必須對相同的mutex加鎖。

      滿足上述條件后,如果一個等待事件A發生在喚醒事件B之前,那么A也同樣在B之前獲得了mutex,那A在被加入喚醒隊列之前B都無法進入喚醒調用,因此保證了B一定能夠喚醒A;試想,如果A、B之間沒有mutex來同步,雖然B在A之后發生,但是可能B喚醒時A尚未被加入到喚醒隊列,這便是所謂的喚醒丟失。

      在線程未獲得相應的互斥鎖時調用pthread_cond_signal或pthread_cond_broadcast函數可能會引起喚醒丟失問題。 喚醒丟失往往會在下面的情況下發生: 一個線程調用pthread_cond_signal或pthread_cond_broadcast函數; 另一個線程正處在測試條件變量和調用pthread_cond_wait函數之間; 沒有線程正在處在阻塞等待的狀態下。

      1

      2

      3

      4

      5

      6

      7

      使用條件變量

      //例子演示了使用Pthreads條件變量的幾個函數。主程序創建了三個線程,兩個線程工作,根系“count”變量。第三個線程等待count變量值達到指定的值。 #include #include #define NUM_THREADS 3 #define TCOUNT 10 #define COUNT_LIMIT 12 int count = 0; int thread_ids[3] = {0,1,2}; pthread_mutex_t count_mutex; pthread_cond_t count_threshold_cv; void *inc_count(void *idp) { int j,i; double result=0.0; int *my_id = idp; for (i=0; i

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      Posix線程 它們那一大家子事兒,要覺得好你就收藏進被窩慢慢看(2)

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      123

      124

      125

      126

      127

      128

      129

      130

      131

      132

      133

      134

      135

      136

      137

      138

      139

      140

      141

      142

      143

      144

      145

      146

      147

      148

      149

      150

      151

      152

      153

      154

      155

      156

      157

      158

      159

      160

      161

      162

      163

      164

      165

      166

      167

      168

      169

      170

      171

      172

      173

      174

      175

      ③線程池

      線程池

      ④Pthread API函數

      任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:兩個橫版A5怎么設置才能打印在同一張A4紙上(怎樣把兩張a5的文檔放在一張a4的紙打印出來)
      下一篇:Excel中2010版進行數據自動篩選的使用方法(Excel2010數據篩選)
      相關文章
      亚洲欧美日韩中文二区| 国产精品亚洲专区无码WEB| 亚洲精品无码久久| 亚洲色偷偷偷综合网| 亚洲国产精品美女| 亚洲国产另类久久久精品| 亚洲中文字幕在线第六区| 亚洲色欲久久久综合网| 亚洲人成影院在线无码按摩店| 337p日本欧洲亚洲大胆裸体艺术 | 精品久久久久久亚洲| 亚洲精品无码aⅴ中文字幕蜜桃| 亚洲欧美国产国产一区二区三区| 亚洲色中文字幕在线播放| 亚洲欧美日韩一区二区三区| 蜜芽亚洲av无码一区二区三区| 美国毛片亚洲社区在线观看| 亚洲国产成人久久一区WWW| 亚洲综合区小说区激情区| 激情综合色五月丁香六月亚洲| 亚洲人成色7777在线观看| 亚洲精品tv久久久久久久久| 久久精品国产精品亚洲艾| 精品日韩亚洲AV无码一区二区三区 | 久久久无码精品亚洲日韩按摩 | 亚洲男人在线无码视频| 国产亚洲情侣一区二区无码AV| 亚洲无人区午夜福利码高清完整版| 亚洲精品无码mv在线观看网站| 亚洲AV无一区二区三区久久| 久久久久亚洲精品日久生情| xxx毛茸茸的亚洲| 亚洲av无码专区在线电影天堂| yy6080久久亚洲精品| 亚洲∧v久久久无码精品| 久久久久亚洲av无码专区导航 | 亚洲高清偷拍一区二区三区| 亚洲熟妇av一区二区三区漫画| 亚洲av日韩av天堂影片精品| 亚洲性一级理论片在线观看| 亚洲另类自拍丝袜第五页 |