通俗的描述信號(hào)量丧荐,是這么個(gè)東西:
每個(gè)信號(hào)量擁有一個(gè)計(jì)數(shù)器陪捷,sem_post()
可以使該計(jì)數(shù)器+1
(V操作)九杂,sem_wait()
在計(jì)數(shù)器不為0時(shí)迷帜,可以使該計(jì)數(shù)器-1
,否則阻塞直到不為0(P操作)惨奕。
而該計(jì)數(shù)器的存在识颊,就可以限定某個(gè)容器中元素的個(gè)數(shù)允耿。
如果單純的看效果奕删,互斥量+條件變量可以實(shí)現(xiàn)計(jì)數(shù)器為1的信號(hào)量。
優(yōu)缺點(diǎn)
UNP卷二
作者對(duì)于信號(hào)量的評(píng)價(jià)為:
- 信號(hào)量默認(rèn)就是進(jìn)程間共享
對(duì)同一個(gè)信號(hào)量疗认,加鎖和解鎖可以在不同的進(jìn)程或是進(jìn)程進(jìn)行完残。
而互斥量只能有是由加鎖線(xiàn)程解鎖,且默認(rèn)不再進(jìn)程間共享横漏。 - 信號(hào)量有與之關(guān)聯(lián)的一個(gè)值谨设,計(jì)數(shù)器
該值在信號(hào)量結(jié)構(gòu)體內(nèi)部維護(hù)。即使消費(fèi)者還沒(méi)有阻塞在sem_wait()
缎浇,該值也會(huì)遞增扎拣。
相比與條件變量,如果消費(fèi)者還沒(méi)阻塞在pthread_cond_wait()
素跺,那么由pthread_cond_signal()
發(fā)送的信號(hào)就會(huì)丟失二蓝,沒(méi)有函數(shù)去處理。 - 相比于其他鎖指厌,只有
sem_port()
是異步信號(hào)安全函數(shù)
異步信號(hào)安全函數(shù)指的是:可以在信號(hào)處理函數(shù)中調(diào)用的函數(shù)刊愚。
muduo陳碩
- 信號(hào)量不是必備的鎖
使用條件標(biāo)量和互斥量可以完全代替信號(hào)量的功能 - 信號(hào)量的計(jì)數(shù)器是個(gè)累贅
程序的容器有自己的長(zhǎng)度,而信號(hào)量又自帶一個(gè)踩验,這樣造成了同樣的信息維護(hù)兩份鸥诽,需要時(shí)刻保持一致商玫。增大了程序員的負(fù)擔(dān)和出錯(cuò)的可能。 - 同時(shí)建議使用單獨(dú)一個(gè)線(xiàn)程去分配任務(wù)
其他線(xiàn)程使用條件變量阻塞
個(gè)人見(jiàn)解
沒(méi)有項(xiàng)目經(jīng)驗(yàn)牡借,不保證全對(duì)
- 不同線(xiàn)程間可解鎖
這還真可能是個(gè)累贅拳昌。 - 確實(shí)可以使用條件變量+互斥量去代替
- 異步信號(hào)安全函數(shù)
沒(méi)用過(guò),不知道啊钠龙。書(shū)上也將炬藤,可以在函數(shù)內(nèi)向管道內(nèi)寫(xiě)東西的方式來(lái)激活一個(gè)別的線(xiàn)程,解決這些問(wèn)題俊鱼。
Posix 信號(hào)量
Posix信號(hào)量不必在內(nèi)核中維護(hù)刻像。
有名信號(hào)量
這個(gè)信號(hào)量有名字啦,根據(jù)這個(gè)名字就可以在不同的進(jìn)程間使用并闲。
這個(gè)名字可以時(shí)文件系統(tǒng)中對(duì)應(yīng)的名字來(lái)表示细睡。
Api
打開(kāi)/創(chuàng)建有名信號(hào)量
#include <semaphore.h>
sem_t sem;
sem_t *sem_open(const char *pathfile, int flag/, mode_t mode ,unsigned int value/);
打開(kāi)一個(gè)信號(hào)量
flag
:可以時(shí)0,主要使用來(lái),當(dāng)指定的文件不存在時(shí)帝火,使用O_CREATE | O_EXEL
新建溜徙,如果指定為0,后兩個(gè)參數(shù)可省略,否則后面兩個(gè)參數(shù)需要帶上犀填。
mode
:文件權(quán)限蠢壹。
value
:信號(hào)量初始的值,這這個(gè)參數(shù)只有在新創(chuàng)建的時(shí)候才需要設(shè)置九巡,如果是打開(kāi)已有的图贸,不需要在去指定,否則會(huì)報(bào)錯(cuò)冕广。該值不超過(guò)是SEM_VALUE_MAX
(至少是32767
)疏日。
取消對(duì)信號(hào)量的使用
#include <semaphore.h>
int sem_close(sem_t *sem);
//成功返回0,否則返回-1
這個(gè)函數(shù)只是聲明撒汉,在這個(gè)進(jìn)程中不再使用這個(gè)信號(hào)量沟优,并不是去析構(gòu)該信號(hào)量。
同時(shí)進(jìn)程結(jié)束的時(shí)候睬辐,無(wú)論是正常還是信號(hào)中斷退出進(jìn)程挠阁,內(nèi)核都會(huì)主動(dòng)調(diào)用該函數(shù)去關(guān)閉進(jìn)程使用的信號(hào)量。
即使都沒(méi)有后進(jìn)程在使用這個(gè)信號(hào)量了溯饵,內(nèi)核也會(huì)維持這個(gè)信號(hào)量侵俗。
也就是說(shuō),Posix的信號(hào)量是隨著內(nèi)核持續(xù)的丰刊。
主動(dòng)析構(gòu)信號(hào)量
#include <semaphore.h>
int sem_unlink(const char *name);
//成功返回0,否則-1
對(duì)打開(kāi)的信號(hào)量的路徑執(zhí)行坡慌,直接刪除指定的文件,但是并不析構(gòu)該信號(hào)量藻三。當(dāng)最后一個(gè)使用該信號(hào)量的進(jìn)程調(diào)用sem_close()
對(duì)該信號(hào)量的時(shí)候洪橘,內(nèi)核析構(gòu)該信號(hào)量跪者。
P操作
#include <semaphore.h>
int sme_wait(sem_t *);
int sem_trywait(sem_t *);
//成功返回0 ,否則-1
sem_wait()
測(cè)試指定的信號(hào)量,如果計(jì)數(shù)器值大于0,那么遞減計(jì)數(shù)器熄求,并立即返回渣玲,否則,阻塞在計(jì)數(shù)器為0弟晚。直到不是0時(shí)忘衍,遞減并返回。如果因?yàn)樾盘?hào)中斷,則過(guò)返回EAGAIN
錯(cuò)誤卿城。
sem_trywait()
函數(shù)枚钓,如果指定信號(hào)量的計(jì)數(shù)器為0,那么直接返回EAGAIN
錯(cuò)誤。
為什么阻塞遞減叫做P操作瑟押?源自荷蘭單詞proberen
意思是嘗試搀捷。
V操作
#include <semaphore.h>
int sme_post(sem_t *);
//成功返回0 ,否則-1
遞增指定的信號(hào)量計(jì)數(shù)器+1
同樣因?yàn)楹商m單詞verhogen
增加的意思。
當(dāng)前計(jì)數(shù)器的值
#include <semaphore.h>
int sem_getvalue(sem_t *,int *);
//成功返回0 ,否則-1
傳入兩個(gè)參數(shù)多望,第二個(gè)參數(shù)是需要填充的嫩舟。
如果當(dāng)前信號(hào)量已經(jīng)上鎖,也就是有線(xiàn)程在等待怀偷,那么該值為0
或者是負(fù)數(shù)家厌,而如果是負(fù)數(shù),那么表示等待該信號(hào)量解鎖的線(xiàn)程數(shù)椎工。
信號(hào)量死鎖
主要出現(xiàn)在饭于,如果同時(shí)使用兩個(gè)信號(hào)量,那么順序一定不能出錯(cuò)维蒙。
基于內(nèi)存信號(hào)量
不使用文件系統(tǒng)標(biāo)識(shí)掰吕,直接存在程序運(yùn)行的內(nèi)存中,(非共享內(nèi)存)木西。
這樣就造成了畴栖,不同進(jìn)程之間不能訪(fǎng)問(wèn)随静,不能用于不同進(jìn)程之間相互訪(fǎng)問(wèn)八千。
一個(gè)父進(jìn)程初始化一個(gè)信號(hào)量,然后fork
其副本得到的是該信號(hào)量的副本燎猛,這兩個(gè)信號(hào)量之間并不存在關(guān)系恋捆。
初始化
#include <semaphore.h >
int sem_init(sem_t *sem,int shared,unsignel int value);
//出錯(cuò)返回-1,成功的不一定。
int sem_destory(sem_t *);
//成功0,失敗-1;
第二個(gè)參數(shù)重绷,表示是否在進(jìn)程件共享沸停,在這種實(shí)現(xiàn)中不可能進(jìn)程間共享,需要基于共享內(nèi)存的信號(hào)量昭卓,才可以愤钾。
sem_init()
需要用戶(hù)自己創(chuàng)建一個(gè)結(jié)構(gòu)體(不是指針)瘟滨。然后使用該函數(shù)去初始化結(jié)構(gòu)體。
而sem_open()
則可以直接返回一個(gè)指針能颁,并不需要去創(chuàng)建這個(gè)結(jié)構(gòu)體杂瘸。
基于共享內(nèi)存的信號(hào)量
和共享內(nèi)存有關(guān)了