信号量,互斥锁,条件变量的联系与区别
轉(zhuǎn)自:http://blog.chinaunix.net/u3/108685/showart_2127853.html
信號(hào)量用在多線程多任務(wù)同步的,一個(gè)線程完成了某一個(gè)動(dòng)作就通過信號(hào)量告訴別的線程,別的線程再進(jìn)行某些動(dòng)作(大家都在semtake的時(shí)候,就阻塞在哪里)。而互斥鎖是用在多線程多任務(wù)互斥的,一個(gè)線程占用了某一個(gè)資源,那么別的線程就無法訪問,直到這個(gè)線程unlock,其他的線程才開始可以利用這個(gè)資源。比如對(duì)全局變量的訪問,有時(shí)要加鎖,操作完了,在解鎖。有的時(shí)候鎖和信號(hào)量會(huì)同時(shí)使用的”
也就是說,信號(hào)量不一定是鎖定某一個(gè)資源,而是流程上的概念,比如:有A,B兩個(gè)線程,B線程要等A線程完成某一任務(wù)以后再進(jìn)行自己下面的步驟,這個(gè)任務(wù)并不一定是鎖定某一資源,還可以是進(jìn)行一些計(jì)算或者數(shù)據(jù)處理之類。而線程互斥量則是“鎖住某一資源”的概念,在鎖定期間內(nèi),其他線程無法對(duì)被保護(hù)的數(shù)據(jù)進(jìn)行操作。在有些情況下兩者可以互換。?
兩者之間的區(qū)別:
| ? | 作用域 | 上鎖時(shí) |
| 信號(hào)量 | 進(jìn)程間或線程間(linux僅線程間) | 只要信號(hào)量的value大于0,其他線程就可以sem_wait成功,成功后信號(hào)量的value減一。若value值不大于0,則sem_wait阻塞,直到sem_post釋放后value值加一 |
| 互斥鎖 | 線程間 | 只要被鎖住,其他任何線程都不可以訪問被保護(hù)的資源? 成功后否則就阻塞 |
以下是信號(hào)燈(量)的一些概念:?
信號(hào)燈與互斥鎖和條件變量的主要不同在于”燈”的概念,燈亮則意味著資源可用,燈滅則意味著不可用。如果說后兩中同步方式側(cè)重于”等待”操作,即資源不可用的話,信號(hào)燈機(jī)制則側(cè)重于點(diǎn)燈,即告知資源可用;沒有等待線程的解鎖或激發(fā)條件都是沒有意義的,而沒有等待燈亮的線程的點(diǎn)燈操作則有效,且能保持燈亮狀態(tài)。當(dāng)然,這樣的操作原語也意味著更多的開銷。?
信號(hào)燈的應(yīng)用除了燈亮/燈滅這種二元燈以外,也可以采用大于1的燈數(shù),以表示資源數(shù)大于1,這時(shí)可以稱之為多元燈。?
1. 創(chuàng)建和 注銷?
POSIX信號(hào)燈標(biāo)準(zhǔn)定義了有名信號(hào)燈和無名信號(hào)燈兩種,但LinuxThreads的實(shí)現(xiàn)僅有無名燈,同時(shí)有名燈除了總是可用于多進(jìn)程之間以外,在使用上與無名燈并沒有很大的區(qū)別,因此下面僅就無名燈進(jìn)行討論。?
int sem_init(sem_t *sem, int pshared, unsigned int value)?
這是創(chuàng)建信號(hào)燈的API,其中value為信號(hào)燈的初值,pshared表示是否為多進(jìn)程共享而不僅僅是用于一個(gè)進(jìn)程。LinuxThreads沒有實(shí)現(xiàn)多進(jìn)程共享信號(hào)燈,因此所有非0值的pshared輸入都將使sem_init()返回-1,且置errno為ENOSYS。初始化好的信號(hào)燈由sem變量表征,用于以下點(diǎn)燈、滅燈操作。?
int sem_destroy(sem_t * sem)?
被注銷的信號(hào)燈sem要求已沒有線程在等待該信號(hào)燈,否則返回-1,且置errno為EBUSY。除此之外,LinuxThreads的信號(hào)燈 注銷函數(shù)不做其他動(dòng)作。?
2. 點(diǎn)燈和滅燈?
int sem_post(sem_t * sem)?
點(diǎn)燈操作將信號(hào)燈值原子地加1,表示增加一個(gè)可訪問的資源。?
int sem_wait(sem_t * sem)?
int sem_trywait(sem_t * sem)?
sem_wait()為等待燈亮操作,等待燈亮(信號(hào)燈值大于0),然后將信號(hào)燈原子地減1,并返回。sem_trywait()為sem_wait()的非阻塞版,如果信號(hào)燈計(jì)數(shù)大于0,則原子地減1并返回0,否則立即返回-1,errno置為EAGAIN。?
3. 獲取燈值?
int sem_getvalue(sem_t * sem, int * sval)?
讀取sem中的燈計(jì)數(shù),存于*sval中,并返回0。?
4. 其他?
sem_wait()被實(shí)現(xiàn)為取消點(diǎn),而且在支持原子”比較且交換”指令的體系結(jié)構(gòu)上,sem_post()是唯一能用于異步信號(hào)處理函數(shù)的POSIX異步信號(hào) 安全的API。?
----------------------------?
線程同步:何時(shí)互斥鎖不夠,還需要條件變量?
?
假設(shè)有共享的資源sum,與之相關(guān)聯(lián)的mutex 是lock_s.假設(shè)每個(gè)線程對(duì)sum的操作很簡(jiǎn)單的,與sum的狀態(tài)無關(guān),比如只是sum++.那么只用mutex足夠了.程序員只要確保每個(gè)線程操作前,取得lock,然后sum++,再unlock即可.每個(gè)線程的代碼將像這樣
add()?
{??
??? pthread_mutex_lock(lock_s);?
??? sum++;?
??? pthread_mutex_unlock(lock_s);?
}
如果操作比較復(fù)雜,假設(shè)線程t0,t1,t2的操作是sum++,而線程t3則是在sum到達(dá)100的時(shí)候,打印出一條信息,并對(duì)sum清零. 這種情況下,如果只用mutex, 則t3需要一個(gè)循環(huán),每個(gè)循環(huán)里先取得lock_s,然后檢查sum的狀態(tài),如果sum>=100,則打印并清零,然后unlock.如果sum<100,則unlock,并sleep()本線程合適的一段時(shí)間.?
這個(gè)時(shí)候,t0,t1,t2的代碼不變,t3的代碼如下
print()
{ while(1) { pthread_mutex_lock(lock_s); if
(sum<100) { printf
(“sum reach 100!”); pthread_mutex_unlock(lock_s); } else{ pthread_mutex_unlock(lock_s); my_thread_sleep(100); returnOK; } }
}
這種辦法有兩個(gè)問題?
1) sum在大多數(shù)情況下不會(huì)到達(dá)100,那么對(duì)t3的代碼來說,大多數(shù)情況下,走的是else分支,只是lock和unlock,然后sleep().這浪費(fèi)了CPU處理時(shí)間.?
2) 為了節(jié)省CPU處理時(shí)間,t3會(huì)在探測(cè)到sum沒到達(dá)100的時(shí)候sleep()一段時(shí)間.這樣卻又帶來另外一個(gè)問題,亦即t3響應(yīng)速度下降.可能在sum到達(dá)200的時(shí)候,t3才會(huì)醒過來.?
3) 這樣,程序員在設(shè)置sleep()時(shí)間的時(shí)候陷入兩難境地,設(shè)置得太短了節(jié)省不了資源,太長了又降低響應(yīng)速度.真是難辦啊!
這個(gè)時(shí)候,condition variable內(nèi)褲外穿,從天而降,拯救了焦頭爛額的你.?
你首先定義一個(gè)condition variable.?
??? pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;?
t0,t1,t2的代碼只要后面加兩行,像這樣
add()
{ pthread_mutex_lock(lock_s); sum++; pthread_mutex_unlock(lock_s); if
(sum>=100) pthread_cond_signal(&cond_sum_ready);
}
而t3的代碼則是
print
{ pthread_mutex_lock(lock_s); while
(sum<100) pthread_cond_wait(&cond_sum_ready, &lock_s); printf
(“sum is over 100!”); sum=0; pthread_mutex_unlock(lock_s); returnOK;
}
注意兩點(diǎn):
1) 在thread_cond_wait()之前,必須先lock相關(guān)聯(lián)的mutex, 因?yàn)榧偃缒繕?biāo)條件未滿足,pthread_cond_wait()實(shí)際上會(huì)unlock該mutex, 然后block,在目標(biāo)條件滿足后再重新lock該mutex, 然后返回.
2) 為什么是while(sum<100),而不是if(sum<100) ?這是因?yàn)樵趐thread_cond_signal()和pthread_cond_wait()返回之間,有時(shí)間差,假設(shè)在這個(gè)時(shí)間差內(nèi),還有另外一個(gè)線程t4又把sum減少到100以下了,那么t3在pthread_cond_wait()返回之后,顯然應(yīng)該再檢查一遍sum的大小.
這就是用 while的用意
總結(jié)
以上是生活随笔為你收集整理的信号量,互斥锁,条件变量的联系与区别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 水稻烘干机多少钱一台?
- 下一篇: 验证码识别(纯数字)