日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux——线程通信(1)

發(fā)布時間:2024/7/19 linux 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux——线程通信(1) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 1.同步概念
  • 2.線程同步
  • 3.數(shù)據(jù)混亂原因:
  • 4.互斥量 mutex
  • 5.mutex 主要應用函數(shù):
    • 5.1 pthread_mutex_init 函數(shù)
    • 5.2 pthread_mutex_destroy 函數(shù)
    • 5.3 pthread_mutex_lock 函數(shù)
    • 5.4 pthread_mutex_unlock 函數(shù)
    • 5.5 pthread_mutex_trylock 函數(shù)
    • 5.6 加鎖與解鎖
    • 5.7 lock 與 trylock:
  • 6.加鎖代碼演示
  • 7.死鎖
  • 8.如何解決死鎖
  • 9.讀寫鎖
    • 9.1 讀寫鎖狀態(tài):
    • 9.2 讀寫鎖特性:
  • 10.讀寫鎖函數(shù)
    • 10.1 pthread_rwlock_init 函數(shù)
    • 10.2 pthread_rwlock_destroy 函數(shù)
    • 10.3 pthread_rwlock_rdlock 函數(shù)
    • 10.4 pthread_rwlock_wrlock 函數(shù)
    • 10.5 pthread_rwlock_unlock 函數(shù)
    • 10.6 pthread_rwlock_tryrdlock 函數(shù)
    • 10.7 讀寫鎖示例

1.同步概念

所謂同步,即同時起步,協(xié)調一致。不同的對象,對“同步”的理解方式略有不同。 如,設備同步,是指在兩個設備之間規(guī)定一個共同的時間參考; 數(shù)據(jù)庫同步,是指讓兩個或多個數(shù)據(jù)庫內容保持一致,或者按需要部分保持一致; 文件同步,是指讓兩個或多個文件夾里的文件保持一致。等等而編程中、通信中所說的同步與生活中大家印象中的同步概念略有差異。 “同”字應是指協(xié)同、協(xié)助、互相配合。主旨在協(xié)同步調,按預定的先后次序運行。

2.線程同步

同步即協(xié)同步調,按預定的先后次序運行。

線程同步,指一個線程發(fā)出某一功能調用時,在沒有得到結果之前,該調用不返回。 同時其它線程為保證數(shù)據(jù)一致性,不能調用該功能。舉例 1: 銀行存款 5000。柜臺,折:取 3000;提款機,卡:取 3000。剩余:2000 舉例 2: 內存中 100 字節(jié),線程 T1 欲填入全 1, 線程 T2 欲填入全 0。但如果 T1 執(zhí)行了 50 個字節(jié)失去 cpu, T2執(zhí)行,會將 T1 寫過的內容覆蓋。當 T1 再次獲得 cpu 繼續(xù) 從失去 cpu 的位置向后寫入 1, 當執(zhí)行結束,內存中的100 字節(jié),既不是全 1,也不是全 0。產(chǎn)生的現(xiàn)象叫做“與時間有關的錯誤”(time related)。為了避免這種數(shù)據(jù)混亂,線程需要同步。“同步”的目的,是為了避免數(shù)據(jù)混亂,解決與時間有關的錯誤。 實際上,不僅線程間需要同步,進程間、信號間等等都需要同步機制。 因此,所有“多個控制流,共同操作一個共享資源”的情況,都需要同步。

3.數(shù)據(jù)混亂原因:

  • 資源共享(獨享資源則不會)
  • 調度隨機(意味著數(shù)據(jù)訪問會出現(xiàn)競爭)
  • 線程間缺乏必要的同步機制。
  • 以上 3 點中,前兩點不能改變,欲提高效率,傳遞數(shù)據(jù),資源必須共享。只要共享資源,就一定會出現(xiàn)競爭。
    只要存在競爭關系,數(shù)據(jù)就很容易出現(xiàn)混亂。
    所以只能從第三點著手解決。使多個線程在訪問共享資源的時候,出現(xiàn)互斥。

    4.互斥量 mutex

    Linux 中提供一把互斥鎖 mutex(也稱之為互斥量)。 每個線程在對資源操作前都嘗試先加鎖,成功加鎖才能操作,操作結束解鎖。 資源還是共享的,線程間也還是競爭的, 但通過“鎖”就將資源的訪問變成互斥操作,而后與時間有關的錯誤也不會再產(chǎn)生了。但,應注意:同一時刻,只能有一個線程持有該鎖。 當 A 線程對某個全局變量加鎖訪問,B 在訪問前嘗試加鎖,拿不到鎖,B 阻塞。C 線程不去加鎖,而直接訪問 該全局變量,依然能夠訪問,但會出現(xiàn)數(shù)據(jù)混亂。所以,互斥鎖實質上是操作系統(tǒng)提供的一把“建議鎖”(又稱“協(xié)同鎖”),建議程序中有多線程訪問共享資源 的時候使用該機制。但,并沒有強制限定。 因此,即使有了 mutex,如果有線程不按規(guī)則來訪問數(shù)據(jù),依然會造成數(shù)據(jù)混亂。

    5.mutex 主要應用函數(shù):

    pthread_mutex_init 函數(shù) pthread_mutex_destroy 函數(shù) pthread_mutex_lock 函數(shù) pthread_mutex_trylock 函數(shù) pthread_mutex_unlock 函數(shù) 以上 5 個函數(shù)的返回值都是:成功返回 0, 失敗返回錯誤號。pthread_mutex_t 類型,其本質是一個結構體。為簡化理解,應用時可忽略其實現(xiàn)細節(jié),簡單當成整數(shù)看待。 pthread_mutex_t mutex; 變量 mutex 只有兩種取值 10

    5.1 pthread_mutex_init 函數(shù)

    初始化一個互斥鎖(互斥量) —> 初值可看作 1

    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);1:傳出參數(shù),調用時應傳 &mutex restrict 關鍵字:只用于限制指針,告訴編譯器,所有修改該指針指向內存中內容的操作, 只能通過本指針完成。不能通過除本指針以外的其他變量或指針修改參 2:互斥量屬性。是一個傳入?yún)?shù),通常傳 NULL,選用默認屬性(線程間共享)。 參 APUE.12.4 同步屬性 1. 靜態(tài)初始化:如果互斥鎖 mutex 是靜態(tài)分配的(定義在全局,或加了 static 關鍵字修飾),可以直接使用宏進行初始化。e.g. pthead_mutex_t muetx = PTHREAD_MUTEX_INITIALIZER; 3. 動態(tài)初始化:局部變量應采用動態(tài)初始化。e.g. pthread_mutex_init(&mutex, NULL)

    5.2 pthread_mutex_destroy 函數(shù)

    銷毀一個互斥鎖

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    5.3 pthread_mutex_lock 函數(shù)

    加鎖。可理解為將 mutex–(或 -1),操作后 mutex 的值為 0。

    int pthread_mutex_lock(pthread_mutex_t *mutex);

    5.4 pthread_mutex_unlock 函數(shù)

    解鎖。可理解為將 mutex ++(或 +1),操作后 mutex 的值為 1。

    int pthread_mutex_unlock(pthread_mutex_t *mutex);

    5.5 pthread_mutex_trylock 函數(shù)

    嘗試加鎖

    int pthread_mutex_trylock(pthread_mutex_t *mutex);

    5.6 加鎖與解鎖

    lock 與 unlock: lock 嘗試加鎖,如果加鎖不成功,線程阻塞,阻塞到持有該互斥量的其他線程解鎖為止。 unlock 主動解鎖函數(shù),同時將阻塞在該鎖上的所有線程全部喚醒,至于哪個線程先被喚醒, 取決于優(yōu)先級、調度。默認:先阻塞、先喚醒。例如:T1 T2 T3 T4 使用一把 mutex 鎖。T1 加鎖成功,其他線程均阻塞,直至 T1 解鎖。 T1 解鎖后,T2 T3 T4 均被喚醒,并自動再次嘗試加鎖。 可假想 mutex 鎖 init 成功初值為 1。lock 功能是將 mutex--。而 unlock 則將 mutex++。

    5.7 lock 與 trylock:

    lock 加鎖失敗會阻塞,等待鎖釋放。 trylock 加鎖失敗直接返回錯誤號(如:EBUSY),不阻塞。

    6.加鎖代碼演示

    #include <stdio.h> #include <pthread.h> #include <unistd.h>void *tfn(void *arg) { srand(time(NULL));while (1) {printf("hello ");sleep(rand() % 3); /*模擬長時間操作共享資源,導致 cpu 易主,產(chǎn)生與時間有關的錯誤*/printf("world\n");sleep(rand() % 3);}return NULL; } int main(void) {pthread_t tid;srand(time(NULL));pthread_create(&tid, NULL, tfn, NULL);while (1) {printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");sleep(rand() % 3);}pthread_join(tid, NULL);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_mutex HELLO hello world WORLD HELLO hello WORLD HELLO WORLD HELLO world WORLD hello HELLO WORLD HELLO world WORLD hello world HELLO WORLD ^Z [1]+ 已停止 ./pthread_mutex #include <stdio.h> #include <pthread.h> #include <unistd.h>pthread_mutex_t mutex;void *tfn(void *arg) { srand(time(NULL));while (1) {pthread_mutex_lock(&mutex);printf("hello ");sleep(rand() % 3); /*模擬長時間操作共享資源,導致 cpu 易主,產(chǎn)生與時間有關的錯誤*/printf("world\n");pthread_mutex_unlock(&mutex);sleep(rand() % 3);}return NULL; } int main(void) {pthread_t tid;srand(time(NULL));pthread_mutex_init(&mutex,NULL);//mutex=1pthread_create(&tid, NULL, tfn, NULL);while (1) {pthread_mutex_lock(&mutex);printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");pthread_mutex_unlock(&mutex);sleep(rand() % 3);}pthread_join(tid, NULL);pthread_mutex_destroy(&mutex);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_mutex HELLO WORLD hello world HELLO WORLD hello world HELLO WORLD hello world HELLO WORLD hello world HELLO WORLD HELLO WORLD hello world HELLO WORLD hello world HELLO WORLD ^Z [4]+ 已停止 ./pthread_mutex

    結論:
    在訪問共享資源前加鎖,訪問結束后立即解鎖。鎖的“粒度”應越小越好。

    7.死鎖

  • 線程試圖對同一個互斥量 A 加鎖兩次。
  • 線程 1 擁有 A 鎖,請求獲得 B 鎖;線程 2 擁有 B 鎖,請求獲得 A 鎖
  • 以上為死鎖的兩種情況。

    #include <stdio.h> #include <pthread.h> #include <unistd.h>pthread_mutex_t mutex;void *tfn(void *arg) { srand(time(NULL));while (1) {pthread_mutex_lock(&mutex);printf("hello ");sleep(rand() % 3); /*模擬長時間操作共享資源,導致 cpu 易主,產(chǎn)生與時間有關的錯誤*/printf("world\n");pthread_mutex_lock(&mutex);/*加鎖兩次,死鎖*/sleep(rand() % 3);}return NULL; } int main(void) {pthread_t tid;srand(time(NULL));pthread_mutex_init(&mutex,NULL);//mutex=1pthread_create(&tid, NULL, tfn, NULL);while (1) {pthread_mutex_lock(&mutex);printf("HELLO ");sleep(rand() % 3);printf("WORLD\n");pthread_mutex_unlock(&mutex);sleep(rand() % 3);}pthread_join(tid, NULL);pthread_mutex_destroy(&mutex);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_mutex_death HELLO WORLD hello world ^Z [5]+ 已停止 ./pthread_mutex_death #include <stdio.h> #include <pthread.h> #include <unistd.h>pthread_mutex_t mutex_A; pthread_mutex_t mutex_B;void *tfn(void *arg) { srand(time(NULL));while (1) {pthread_mutex_lock(&mutex_B);sleep(1);pthread_mutex_lock(&mutex_A);printf("hello ");printf("world\n");pthread_mutex_unlock(&mutex_A);pthread_mutex_unlock(&mutex_B);sleep(rand() % 3);}return NULL; } int main(void) {pthread_t tid;srand(time(NULL));pthread_mutex_init(&mutex_A,NULL);//mutex=1pthread_mutex_init(&mutex_B,NULL);pthread_create(&tid, NULL, tfn, NULL);while (1) {pthread_mutex_lock(&mutex_A);sleep(1);pthread_mutex_lock(&mutex_B);printf("HELLO ");printf("WORLD\n");pthread_mutex_unlock(&mutex_B);pthread_mutex_unlock(&mutex_A);sleep(rand() % 3);}pthread_join(tid, NULL);pthread_mutex_destroy(&mutex_A);pthread_mutex_destroy(&mutex_B);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_mutex_death ^Z [6]+ 已停止 ./pthread_mutex_death

    8.如何解決死鎖

    使用pthread_mutex_trylock函數(shù),嘗試加鎖,若不成功,就釋放自己手中的已有的鎖。 #include <stdio.h> #include <pthread.h> #include <unistd.h>pthread_mutex_t mutex_A; pthread_mutex_t mutex_B;void *tfn(void *arg) { srand(time(NULL));while (1) {int death_pid;pthread_mutex_lock(&mutex_B);sleep(1);if(pthread_mutex_trylock(&mutex_A)!=0){pthread_mutex_unlock(&mutex_B);printf("trylock fail,delete mutex_B\n");sleep(1);}else{printf("hello ");printf("world\n");pthread_mutex_unlock(&mutex_A);pthread_mutex_unlock(&mutex_B);sleep(rand() % 3);}}return NULL; } int main(void) {pthread_t tid;srand(time(NULL));pthread_mutex_init(&mutex_A,NULL);//mutex=1pthread_mutex_init(&mutex_B,NULL);pthread_create(&tid, NULL, tfn, NULL);while (1) {pthread_mutex_lock(&mutex_A);sleep(1);pthread_mutex_lock(&mutex_B);printf("HELLO ");printf("WORLD\n");pthread_mutex_unlock(&mutex_B);pthread_mutex_unlock(&mutex_A);sleep(rand() % 3);}pthread_join(tid, NULL);pthread_mutex_destroy(&mutex_A);pthread_mutex_destroy(&mutex_B);return 0; } zhaoxr@zhaoxr-ThinkPad-E450:~/pthread$ ./pthread_mutex_death trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD HELLO trylock fail,delete mutex_B WORLD trylock fail,delete mutex_B HELLO WORLD hello world HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD trylock fail,delete mutex_B HELLO WORLD hello world HELLO WORLD hello world ^Z [11]+ 已停止 ./pthread_mutex_death

    9.讀寫鎖

    與互斥量類似,但讀寫鎖允許更高的并行性。其特性為:寫獨占,讀共享。 讀寫鎖也叫共享-獨占鎖。 當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的; 當它以寫模式鎖住時,它是以獨占模式鎖住的。 寫獨占、讀共享。 讀寫鎖非常適合于對數(shù)據(jù)結構讀的次數(shù)遠大于寫的情況。

    9.1 讀寫鎖狀態(tài):

    特別強調:讀寫鎖只有一把,但其具備兩種狀態(tài):

  • 讀模式下加鎖狀態(tài) (讀鎖)
  • 寫模式下加鎖狀態(tài) (寫鎖)
  • 9.2 讀寫鎖特性:

  • 讀寫鎖是“寫模式加鎖”時, 解鎖前,所有對該鎖加鎖的線程都會被阻塞。
  • 讀寫鎖是“讀模式加鎖”時, 如果線程以讀模式對其加鎖會成功;如果線程以寫模式加鎖會阻塞。
  • 讀寫鎖是“讀模式加鎖”時, 既有試圖以寫模式加鎖的線程,也有試圖以讀模式加鎖的線程。那么讀寫鎖會阻塞隨后的讀模式鎖請求。優(yōu)先滿足寫模式鎖。讀鎖、寫鎖并行阻塞,寫鎖優(yōu)先級高
  • 10.讀寫鎖函數(shù)

    pthread_rwlock_init 函數(shù) pthread_rwlock_destroy 函數(shù) pthread_rwlock_rdlock 函數(shù) pthread_rwlock_wrlock 函數(shù) pthread_rwlock_tryrdlock 函數(shù) pthread_rwlock_trywrlock 函數(shù) pthread_rwlock_unlock 函數(shù) 以上 7 個函數(shù)的返回值都是:成功返回 0, 失敗直接返回錯誤號。pthread_rwlock_t 類型 用于定義一個讀寫鎖變量。 pthread_rwlock_t rwlock;

    10.1 pthread_rwlock_init 函數(shù)

    初始化一把讀寫鎖

    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); 參 2:attr 表讀寫鎖屬性,通常使用默認屬性,傳 NULL 即可。

    10.2 pthread_rwlock_destroy 函數(shù)

    銷毀一把讀寫鎖

    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

    10.3 pthread_rwlock_rdlock 函數(shù)

    以讀方式請求讀寫鎖。(常簡稱為:請求讀鎖)

    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

    10.4 pthread_rwlock_wrlock 函數(shù)

    以寫方式請求讀寫鎖。(常簡稱為:請求寫鎖)

    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

    10.5 pthread_rwlock_unlock 函數(shù)

    解鎖

    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

    10.6 pthread_rwlock_tryrdlock 函數(shù)

    非阻塞以讀方式請求讀寫鎖(非阻塞請求讀鎖)

    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

    10.7 讀寫鎖示例

    #include <stdio.h> #include <unistd.h> #include <pthread.h>int counter; pthread_rwlock_t rwlock;/* 3 個線程不定時寫同一全局資源,5 個線程不定時讀同一全局資源 */ void *th_write(void *arg) {int t, i = (int)arg;while (1) {pthread_rwlock_wrlock(&rwlock);t = counter;usleep(1000);printf("=======write %d: %lu: counter=%d ++counter=%d\n", i, pthread_self(), t, ++counter);pthread_rwlock_unlock(&rwlock);usleep(10000);}return NULL; } void *th_read(void *arg) {int i = (int)arg;while (1) {pthread_rwlock_rdlock(&rwlock);printf("----------------------------read %d: %lu: %d\n", i, pthread_self(), counter);pthread_rwlock_unlock(&rwlock);usleep(2000);}return NULL; } int main(void) {int i;pthread_t tid[8];pthread_rwlock_init(&rwlock, NULL);for (i = 0; i < 3; i++)pthread_create(&tid[i], NULL, th_write, (void *)i);for (i = 0; i < 5; i++)pthread_create(&tid[i+3], NULL, th_read, (void *)i);for (i = 0; i < 8; i++)pthread_join(tid[i], NULL);pthread_rwlock_destroy(&rwlock);return 0; }

    總結

    以上是生活随笔為你收集整理的linux——线程通信(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。