信号量 Linux(linux信号量编程)
spinlock和Semaphore信號(hào)量的區(qū)別?
Mutex是一把鑰匙,一個(gè)人拿了就可進(jìn)入一個(gè)房間,出來(lái)的時(shí)候把鑰匙交給隊(duì)列的第一個(gè)。一般的用法是用于串行化對(duì)critical section代碼的訪問(wèn),保證這段代碼不會(huì)被并行的運(yùn)行。
Semaphore是一件可以容納N人的房間,如果人不滿(mǎn)就可以進(jìn)去,如果人滿(mǎn)了,就要等待有人出來(lái)。對(duì)于N=1的情況,稱(chēng)為binary semaphore。一般的用法是,用于限制對(duì)于某一資源的同時(shí)訪問(wèn)。
Binary semaphore與Mutex的差異:
在有的系統(tǒng)中Binary semaphore與Mutex是沒(méi)有差異的。在有的系統(tǒng)上,主要的差異是mutex一定要由獲得鎖的進(jìn)程來(lái)釋放。而semaphore可以由其它進(jìn)程釋放(這時(shí)的semaphore實(shí)際就是個(gè)原子的變量,大家可以加或減),因此semaphore可以用于進(jìn)程間同步。Semaphore的同步功能是所有系統(tǒng)都支持的,而Mutex能否由其他進(jìn)程釋放則未定,因此建議mutex只用于保護(hù)critical section。而semaphore則用于保護(hù)某變量,或者同步。
另一個(gè)概念是spin lock,這是一個(gè)內(nèi)核態(tài)概念。spin lock與semaphore的主要區(qū)別是spin lock是busy waiting,而semaphore是sleep。對(duì)于可以sleep的進(jìn)程來(lái)說(shuō),busy waiting當(dāng)然沒(méi)有意義。對(duì)于單CPU的系統(tǒng),busy waiting當(dāng)然更沒(méi)意義(沒(méi)有CPU可以釋放鎖)。因此,只有多CPU的內(nèi)核態(tài)非進(jìn)程空間,才會(huì)用到spin lock。Linux kernel的spin lock在非SMP的情況下,只是關(guān)irq,沒(méi)有別的操作,用于確保該段程序的運(yùn)行不會(huì)被打斷。其實(shí)也就是類(lèi)似mutex的作用,串行化對(duì)critical section的訪問(wèn)。但是mutex不能保護(hù)中斷的打斷,也不能在中斷處理程序中被調(diào)用。而spin lock也一般沒(méi)有必要用于可以sleep的進(jìn)程空間。
---------------------------------------------------------------------------------------------
內(nèi)核同步措施
為了避免并發(fā),防止競(jìng)爭(zhēng)。內(nèi)核提供了一組同步方法來(lái)提供對(duì)共享數(shù)據(jù)的保護(hù)。 我們的重點(diǎn)不是介紹這些方法的詳細(xì)用法,而是強(qiáng)調(diào)為什么使用這些方法和它們之間的差別。
Linux 使用的同步機(jī)制可以說(shuō)從2.0到2.6以來(lái)不斷發(fā)展完善。從最初的原子操作,到后來(lái)的信號(hào)量,從大內(nèi)核鎖到今天的自旋鎖。這些同步機(jī)制的發(fā)展伴隨 Linux從單處理器到對(duì)稱(chēng)多處理器的過(guò)度;伴隨著從非搶占內(nèi)核到搶占內(nèi)核的過(guò)度。鎖機(jī)制越來(lái)越有效,也越來(lái)越復(fù)雜。
目前來(lái)說(shuō)內(nèi)核中原子操作多用來(lái)做計(jì)數(shù)使用,其它情況最常用的是兩種鎖以及它們的變種:一個(gè)是自旋鎖,另一個(gè)是信號(hào)量。我們下面就來(lái)著重介紹一下這兩種鎖機(jī)制。
自旋鎖
自旋鎖是專(zhuān)為防止多處理器并發(fā)而引入的一種鎖,它在內(nèi)核中大量應(yīng)用于中斷處理等部分(對(duì)于單處理器來(lái)說(shuō),防止中斷處理中的并發(fā)可簡(jiǎn)單采用關(guān)閉中斷的方式,不需要自旋鎖)。
自旋鎖最多只能被一個(gè)內(nèi)核任務(wù)持有,如果一個(gè)內(nèi)核任務(wù)試圖請(qǐng)求一個(gè)已被爭(zhēng)用(已經(jīng)被持有)的自旋鎖,那么這個(gè)任務(wù)就會(huì)一直進(jìn)行忙循環(huán)——旋轉(zhuǎn)——等待鎖重新可用。要是鎖未被爭(zhēng)用,請(qǐng)求它的內(nèi)核任務(wù)便能立刻得到它并且繼續(xù)進(jìn)行。自旋鎖可以在任何時(shí)刻防止多于一個(gè)的內(nèi)核任務(wù)同時(shí)進(jìn)入臨界區(qū),因此這種鎖可有效地避免多處理器上并發(fā)運(yùn)行的內(nèi)核任務(wù)競(jìng)爭(zhēng)共享資源。
事實(shí)上,自旋鎖的初衷就是:在短期間內(nèi)進(jìn)行輕量級(jí)的鎖定。一個(gè)被爭(zhēng)用的自旋鎖使得請(qǐng)求它的線程在等待鎖重新可用的期間進(jìn)行自旋(特別浪費(fèi)處理器時(shí)間),所以自旋鎖不應(yīng)該被持有時(shí)間過(guò)長(zhǎng)。如果需要長(zhǎng)時(shí)間鎖定的話(huà), 最好使用信號(hào)量。
自旋鎖的基本形式如下:
spin_lock(&mr_lock);
//臨界區(qū)
spin_unlock(&mr_lock);
因?yàn)樽孕i在同一時(shí)刻只能被最多一個(gè)內(nèi)核任務(wù)持有,所以一個(gè)時(shí)刻只有一個(gè)線程允許存在于臨界區(qū)中。這點(diǎn)很好地滿(mǎn)足了對(duì)稱(chēng)多處理機(jī)器需要的鎖定服務(wù)。在單處理器上,自旋鎖僅僅當(dāng)作一個(gè)設(shè)置內(nèi)核搶占的開(kāi)關(guān)。如果內(nèi)核搶占也不存在,那么自旋鎖會(huì)在編譯時(shí)被完全剔除出內(nèi)核。
簡(jiǎn)單的說(shuō),自旋鎖在內(nèi)核中主要用來(lái)防止多處理器中并發(fā)訪問(wèn)臨界區(qū),防止內(nèi)核搶占造成的競(jìng)爭(zhēng)。另外自旋鎖不允許任務(wù)睡眠(持有自旋鎖的任務(wù)睡眠會(huì)造成自死鎖——因?yàn)樗哂锌赡茉斐沙钟墟i的內(nèi)核任務(wù)被重新調(diào)度,而再次申請(qǐng)自己已持有的鎖),它能夠在中斷上下文中使用。
死鎖:假設(shè)有一個(gè)或多個(gè)內(nèi)核任務(wù)和一個(gè)或多個(gè)資源,每個(gè)內(nèi)核都在等待其中的一個(gè)資源,但所有的資源都已經(jīng)被占用了。這便會(huì)發(fā)生所有內(nèi)核任務(wù)都在相互等待,但它們永遠(yuǎn)不會(huì)釋放已經(jīng)占有的資源,于是任何內(nèi)核任務(wù)都無(wú)法獲得所需要的資源,無(wú)法繼續(xù)運(yùn)行,這便意味著死鎖發(fā)生了。自死瑣是說(shuō)自己占有了某個(gè)資源,然后自己又申請(qǐng)自己已占有的資源,顯然不可能再獲得該資源,因此就自縛手腳了。
信號(hào)量
Linux中的信號(hào)量是一種睡眠鎖。如果有一個(gè)任務(wù)試圖獲得一個(gè)已被持有的信號(hào)量時(shí),信號(hào)量會(huì)將其推入等待隊(duì)列,然后讓其睡眠。這時(shí)處理器獲得自由去執(zhí)行其它代碼。當(dāng)持有信號(hào)量的進(jìn)程將信號(hào)量釋放后,在等待隊(duì)列中的一個(gè)任務(wù)將被喚醒,從而便可以獲得這個(gè)信號(hào)量。
信號(hào)量的睡眠特性,使得信號(hào)量適用于鎖會(huì)被長(zhǎng)時(shí)間持有的情況;只能在進(jìn)程上下文中使用,因?yàn)橹袛嗌舷挛闹惺遣荒鼙徽{(diào)度的;另外當(dāng)代碼持有信號(hào)量時(shí),不可以再持有自旋鎖。
信號(hào)量基本使用形式為:
static DECLARE_MUTEX(mr_sem);//聲明互斥信號(hào)量
if(down_interruptible(&mr_sem))
//可被中斷的睡眠,當(dāng)信號(hào)來(lái)到,睡眠的任務(wù)被喚醒
//臨界區(qū)
up(&mr_sem);
信號(hào)量和自旋鎖區(qū)別
雖然聽(tīng)起來(lái)兩者之間的使用條件復(fù)雜,其實(shí)在實(shí)際使用中信號(hào)量和自旋鎖并不易混淆。注意以下原則:
如果代碼需要睡眠——這往往是發(fā)生在和用戶(hù)空間同步時(shí)——使用信號(hào)量是唯一的選擇。由于不受睡眠的限制,使用信號(hào)量通常來(lái)說(shuō)更加簡(jiǎn)單一些。如果需要在自旋鎖和信號(hào)量中作選擇,應(yīng)該取決于鎖被持有的時(shí)間長(zhǎng)短。理想情況是所有的鎖都應(yīng)該盡可能短的被持有,但是如果鎖的持有時(shí)間較長(zhǎng)的話(huà),使用信號(hào)量是更好的選擇。另外,信號(hào)量不同于自旋鎖,它不會(huì)關(guān)閉內(nèi)核搶占,所以持有信號(hào)量的代碼可以被搶占。這意味者信號(hào)量不會(huì)對(duì)影響調(diào)度反應(yīng)時(shí)間帶來(lái)負(fù)面影響。
自旋鎖對(duì)信號(hào)量
需求 建議的加鎖方法
低開(kāi)銷(xiāo)加鎖 優(yōu)先使用自旋鎖
短期鎖定 優(yōu)先使用自旋鎖
長(zhǎng)期加鎖 優(yōu)先使用信號(hào)量
中斷上下文中加鎖 使用自旋鎖
持有鎖是需要睡眠、調(diào)度 使用信號(hào)量
linux怎么實(shí)現(xiàn)二進(jìn)制信號(hào)?
用echo直接可以十六進(jìn)制寫(xiě)到文件里去。
echo -e -n "x11x22" > test這樣就把兩個(gè)字節(jié)數(shù)據(jù)0x11和0x22寫(xiě)入到了文件test中
總結(jié)
以上是生活随笔為你收集整理的信号量 Linux(linux信号量编程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 嵌入式C中,全局变量滥用的后果竟如此严重
- 下一篇: C语言中面向对象编程