Linux系统编程----16(线程同步,互斥量 mutex,互斥锁的相关函数,死锁,读写锁)
同步概念
所謂同步,即同時(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ù)混亂原因
互斥量 mutex
Linux 中提供一把互斥鎖 mutex(也稱之為互斥量) 。
每個(gè)線程在對(duì)資源操作前都嘗試先加鎖,成功加鎖才能操作,操作結(jié)束解鎖。
但,應(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ù)
初始化一個(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 同步屬性
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);}線程在操作完共享資源后本應(yīng)該立即解鎖,但修改后,線程抱著鎖睡眠。睡醒解鎖后又立即加鎖,這兩個(gè) 庫(kù)函數(shù)本身不會(huì)阻塞。
所以在這兩行代碼之間失去 cpu 的概率很小。因此,另外一個(gè)線程很難得到加鎖的機(jī)會(huì)
注意事項(xiàng):在訪問(wèn)共享資源前加鎖,訪問(wèn)結(jié)束后立即解鎖。鎖的“粒度”應(yīng)越小越好。
死鎖
讀寫鎖
與互斥量類似,但讀寫鎖允許更高的并行性。其特性為:寫?yīng)氄?#xff0c;讀共享。
讀寫鎖狀態(tài)
一把讀寫鎖具備三種狀態(tài):
讀寫鎖特性:
主要應(yīng)用函數(shù):
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)題。
- 上一篇: dnf采矿大亨怎么快速升级
- 下一篇: Linux系统编程---17(条件变量及