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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)

發(fā)布時(shí)間:2023/11/30 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

同步概念

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

線程同步

同步即協(xié)同步調(diào),按預(yù)定的先后次序運(yùn)行。
線程同步,指一個(gè)線程發(fā)出某一功能調(diào)用時(shí),在沒有得到結(jié)果之前,該調(diào)用不返回。同時(shí)其它線程為保證數(shù)據(jù) 一致性,不能調(diào)用該功能。

  • 舉例 1: 銀行存款 5000。柜臺(tái),折:取 3000;提款機(jī),卡:取 3000。剩余:2000

  • 舉例 2: 內(nèi)存中 100 字節(jié),線程 T1 欲填入全 1, 線程 T2 欲填入全 0。但如果 T1 執(zhí)行了 50 個(gè)字節(jié)失去 cpu,T2 執(zhí)行,會(huì)將 T1 寫過(guò)的內(nèi)容覆蓋。當(dāng) T1 再次獲得 cpu 繼續(xù) 從失去 cpu 的位置向后寫入 1,當(dāng)執(zhí)行結(jié)束,內(nèi)存中的 100 字節(jié),既不是全 1,也不是全 0。

    產(chǎn)生的現(xiàn)象叫做“與時(shí)間有關(guān)的錯(cuò)誤”(time related)。為了避免這種數(shù)據(jù)混亂,線程需要同步。
    “同步”的目的,是為了避免數(shù)據(jù)混亂,解決與時(shí)間有關(guān)的錯(cuò)誤。實(shí)際上,不僅線程間需要同步,進(jìn)程間、信 號(hào)間等等都需要同步機(jī)制。
    因此,所有“多個(gè)控制流,共同操作一個(gè)共享資源”的情況,都需要同步。

  • 數(shù)據(jù)混亂原因

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

    Linux 中提供一把互斥鎖 mutex(也稱之為互斥量) 。
    每個(gè)線程在對(duì)資源操作前都嘗試先加鎖,成功加鎖才能操作,操作結(jié)束解鎖。

  • 資源還是共享的,線程間也還是競(jìng)爭(zhēng)的,
  • 但通過(guò)“鎖”就將資源的訪問(wèn)變成互斥操作,而后與時(shí)間有關(guān)的錯(cuò)誤也不會(huì)再產(chǎn)生了。

  • 但,應(yīng)注意:同一時(shí)刻,只能有一個(gè)線程持有該鎖。
    當(dāng) A 線程對(duì)某個(gè)全局變量加鎖訪問(wèn),B 在訪問(wèn)前嘗試加鎖,拿不到鎖,B 阻塞。C 線程不去加鎖,而直接訪問(wèn) 該全局變量,依然能夠訪問(wèn),但會(huì)出現(xiàn)數(shù)據(jù)混亂。
    所以,互斥鎖實(shí)質(zhì)上是操作系統(tǒng)提供的一把“建議鎖”(又稱“協(xié)同鎖”),建議程序中有多線程訪問(wèn)共享資源 的時(shí)候使用該機(jī)制。但,并沒有強(qiáng)制限定。
    因此,即使有了 mutex,如果有線程不按規(guī)則來(lái)訪問(wèn)數(shù)據(jù),依然會(huì)造成數(shù)據(jù)混亂。

    主要應(yīng)用函數(shù):

  • pthread_mutex_init 函數(shù)
  • pthread_mutex_destroy 函數(shù)
  • pthread_mutex_lock 函數(shù)
  • pthread_mutex_trylock 函數(shù)
  • pthread_mutex_unlock 函數(shù)
  • 以上 5 個(gè)函數(shù)的返回值都是:成功返回 0, 失敗返回錯(cuò)誤號(hào)。
  • pthread_mutex_t 類型,其本質(zhì)是一個(gè)結(jié)構(gòu)體。為簡(jiǎn)化理解,應(yīng)用時(shí)可忽略其實(shí)現(xiàn)細(xì)節(jié),簡(jiǎn)單當(dāng)成整數(shù)看待。
  • pthread_mutex_tmutex; 變量 mutex 只有兩種取值 1、0。
  • pthread_mutex_init 函數(shù)

    初始化一個(gè)互斥鎖(互斥量)—> 初值可看作 1 int pthread_mutex_init (pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
    參 1:傳出參數(shù),調(diào)用時(shí)應(yīng)傳 &mutex
    restrict 關(guān)鍵字:只用于限制指針,告訴編譯器,所有修改該指針指向內(nèi)存中內(nèi)容的操作,只能通過(guò)本指針完成。 不能通過(guò)除本指針以外的其他變量或指針修改
    參 2:互斥量屬性。是一個(gè)傳入?yún)?shù),通常傳 NULL,選用默認(rèn)屬性(線程間共享)。 參 APUE.12.4 同步屬性

  • 靜態(tài)初始化:如果互斥鎖 mutex 是靜態(tài)分配的(定義在全局,或加了 static 關(guān)鍵字修飾),可以直接 使用宏進(jìn)行初始化。e.g. pthead_mutex_tmuetx=PTHREAD_MUTEX_INITIALIZER;
  • 動(dòng)態(tài)初始化:局部變量應(yīng)采用動(dòng)態(tài)初始化。e.g. pthread_mutex_init(&mutex,NULL)
  • pthread_mutex_destroy 函數(shù)

    銷毀一個(gè)互斥鎖

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    pthread_mutex_lock 函數(shù)

    加鎖成功。可理解為將 mutex–(或-1)

    int pthread_mutex_lock(pthread_mutex_t *mutex);

    pthread_mutex_unlock 函數(shù)

    解鎖成功。可理解為將 mutex++(或+1)

    int pthread_mutex_unlock(pthread_mutex_t *mutex);

    pthread_mutex_trylock 函數(shù)

    嘗試加鎖

    int pthread_mutex_trylock(pthread_mutex_t *mutex);

    示例:子線程打印小寫,主控線程打印大寫
    #include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> #include<string.h>pthread_mutex_t mutex; //鎖的定義void *tfn(void *arg) {srand(time(NULL));while(1){pthread_mutex_lock(&mutex);printf("hello");sleep(rand() % 3); /*模擬長(zhǎng)時(shí)間操作共享資源,導(dǎo)致cpu易主,產(chǎn)生與時(shí)間>有關(guān)的錯(cuò)誤*/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_mutex_destroy(&mutex);}

  • 定義全局互斥量,初始化 init(&m,NULL)互斥量,添加對(duì)應(yīng)的 destry
  • 兩個(gè)線程 while 中,兩次 printf 前后,分別加 lock 和 unlock
  • 將 unlock 挪至第二個(gè) sleep 后,發(fā)現(xiàn)交替現(xiàn)象很難出現(xiàn)。
    線程在操作完共享資源后本應(yīng)該立即解鎖,但修改后,線程抱著鎖睡眠。睡醒解鎖后又立即加鎖,這兩個(gè) 庫(kù)函數(shù)本身不會(huì)阻塞。
    所以在這兩行代碼之間失去 cpu 的概率很小。因此,另外一個(gè)線程很難得到加鎖的機(jī)會(huì)
  • main 中加 flag=5 將 flg 在 while 中-- 這時(shí),主線程輸出 5 次后試圖銷毀鎖,但子線程未將鎖釋放,無(wú)法 完成。
  • main 中加 pthread_cancel()將子線程取消。
  • 注意事項(xiàng):在訪問(wèn)共享資源前加鎖,訪問(wèn)結(jié)束后立即解鎖。鎖的“粒度”應(yīng)越小越好。

    死鎖

  • 線程試圖對(duì)同一個(gè)互斥量 A 加鎖兩次。
  • 線程 1 擁有 A 鎖,請(qǐng)求獲得 B 鎖;線程 2 擁有 B 鎖,請(qǐng)求獲得 A 鎖
  • 當(dāng)不能獲得所有的鎖時(shí),放棄已經(jīng)占有的鎖
  • 讀寫鎖

    與互斥量類似,但讀寫鎖允許更高的并行性。其特性為:寫?yīng)氄?#xff0c;讀共享。

    讀寫鎖狀態(tài)

    一把讀寫鎖具備三種狀態(tài):

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

  • 讀寫鎖是“寫模式加鎖”時(shí), 解鎖前,所有對(duì)該鎖加鎖的線程都會(huì)被阻塞。
  • 讀寫鎖是“讀模式加鎖”時(shí), 如果線程以讀模式對(duì)其加鎖會(huì)成功;如果線程以寫模式加鎖會(huì)阻塞。
  • 讀寫鎖是“讀模式加鎖”時(shí), 既有試圖以寫模式加鎖的線程,也有試圖以讀模式加鎖的線程。那么讀寫鎖 會(huì)阻塞隨后的讀模式鎖請(qǐng)求。優(yōu)先滿足寫模式鎖。讀鎖、寫鎖并行阻塞,寫鎖優(yōu)先級(jí)高
  • 讀寫鎖也叫共享-獨(dú)占鎖。當(dāng)讀寫鎖以讀模式鎖住時(shí),它是以共享模式鎖住的;當(dāng)它以寫模式鎖住時(shí),它是以獨(dú) 占模式鎖住的。寫?yīng)氄肌⒆x共享
  • 讀寫鎖非常適合于對(duì)數(shù)據(jù)結(jié)構(gòu)讀的次數(shù)遠(yuǎn)大于寫的情況。
  • 主要應(yīng)用函數(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 個(gè)函數(shù)的返回值都是:成功返回 0, 失敗直接返回錯(cuò)誤號(hào)。
  • pthread_rwlock_t 類型 用于定義一個(gè)讀寫鎖變量。
  • pthread_rwlock_trwlock;
  • pthread_rwlock_init 函數(shù)

    初始化一把讀寫鎖
    int pthread_rwlock_init(pthread_rwlock_t *restrictrwlock,const pthread_rwlockattr_t *restrictattr);
    參 2:attr 表讀寫鎖屬性,通常使用默認(rèn)屬性,傳 NULL 即可。

    pthread_rwlock_destroy 函數(shù)

    銷毀一把讀寫鎖

    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    pthread_rwlock_rdlock 函數(shù)

    以讀方式請(qǐng)求讀寫鎖。(常簡(jiǎn)稱為:請(qǐng)求讀鎖)

    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    pthread_rwlock_wrlock 函數(shù)

    以寫方式請(qǐng)求讀寫鎖。(常簡(jiǎn)稱為:請(qǐng)求寫鎖)

    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    pthread_rwlock_unlock 函數(shù)

    解鎖

    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    pthread_rwlock_tryrdlock 函數(shù)

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

    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    pthread_rwlock_trywrlock 函數(shù)

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

    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    同時(shí)有多個(gè)線程對(duì)同一全局?jǐn)?shù)據(jù)讀、寫操作
    #include<stdio.h> #include<unistd.h> #include<pthread.h>int counter; //全局資源pthread_rwlock_t rwlock;void *th_write(void *arg) //寫線程 {int t;int i = (int)arg;while(1){t = counter;usleep(1000);pthread_rwlock_wrlock(&rwlock);printf("========write %d: %lu: counter=%d ++counter=%d\n",i,pthread_self(),t,++counter);pthread_rwlock_unlock(&rwlock);usleep(5000);} 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(900);} 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);//三個(gè)寫線程,5個(gè)讀線程for(i = 0; i < 8; i++)pthread_join(tid[i],NULL);pthread_rwlock_destroy(&rwlock); //釋放讀寫鎖return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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