1.概述
systemv訊號量並不如posix訊號量那樣「好用」,但相比之下它的年代更加久遠,但是systemv使用的卻更加廣泛(尤其是在老系統中)。在學習posix訊號量的時候,已經大概清楚了二值訊號量和計數訊號量是什麼東西。在接觸systemv訊號量之後,這裡有乙個新的概念叫做:計數訊號量集。其實就是把訊號量放入陣列中,不過都用一些特別的結構封裝。
1.訊號量結構體
核心為每個訊號量集維護乙個訊號量結構體,可在找到該定義:
struct semid_ds
;struct sem
;
開啟/建立訊號量int semget(key_t key, int nsems, int oflag);函式功能:建立乙個訊號量集或訪問乙個已經存在的訊號量集
返回值:成功返回非負的識別符號,出錯返回-1
引數:
key是訊號量的鍵值,多個程序可以通過這個鍵值訪問同乙個訊號量;
nsems引數指定訊號量集合中的訊號量數,一般設為1,如果不建立新的訊號量集,只是訪問乙個已經存在的集合,可以把該引數設為0,一旦建立完乙個訊號量集,就不能改變其中的訊號量數;
oflag同open()許可權位,ipc_creat標示建立新的訊號量,如果或上ipc_excl,若訊號量已存在則出錯,如果沒有或上ipc_excl,若訊號量存在也不會出錯。
操作/控制訊號量
int semctl(int semid, int semnum, int cmd, … /*union semun arg */);
函式功能:該函式用來直接控制訊號量資訊.也就是直接刪除訊號量或者初始化訊號量.
返回值:若成功,根據cmd不同返回不同的值,ipc_stat,ipc_setval,ipc_rmid返回0,ipc_getval返回訊號量當前值;出錯返回-1.
引數:
semid標示操作的訊號量集;
semnum標示該訊號量集內的某個成員陣列下標索引,通常取值0,也就是第乙個訊號量;
cmd:指定對單個訊號量的各種操ipc_stat,ipc_getval,ipc_setval,ipc_rmid;
;arg: 可選引數,取決了第三個引數cmd,由此可以看見,有些成員僅僅針對某些命令,這也正是為什麼這裡用union而不用struct,可以節省空間,因為假設當前命令跟某個成員沒關的時候,struct依然為這個成員分配空間。
union semun
;注意:該聯合體沒有定義在任何系統標頭檔案中,因此得使用者自己宣告,centos6.
5中/linux/sem.h可以找到
semid_ds 資料結構在標頭檔案 有如下定義:
struct semid_ds
;struct ipc_perm
;
*int semop(int semid, struct sembuf sops, unsigned nsops);
注釋:用來改變訊號量的值,該函式是具有原子性的
功能:開啟乙個訊號量集合後,對其中乙個或多個訊號量操作(p/v加減操作)
對於struct sembuf這個結構體來說,其結構定義如下:
struct sembuf
;
sem_num指定特定訊號量的操作。
sem_op的值分為3類:
a.sem_op > 0:將值新增到semval上,對應與釋放某個資源(v操作,生產操作)。
b.sem_op = 0:希望等待到semval值變為0,如果已經是0,則立即返回,否則semzcnt+1,並執行緒阻塞。
c.sem_op < 0:希望等待到semval值變為大於或等於|sem_op|(希望得到sem_op個數的資源,也就是sem_op的絕對值大於等於剩餘的資源數量semval,如果不滿足就阻塞,等到條件滿足),這對應分配資源(p操作,消費操作)。如果已經滿足條件,則semval減去sem_op的絕對值,否則semncnt+1並且執行緒投入睡眠。
nops是opstr陣列中元素數目,通常取值為1。
systemv訊號量的一般程式設計步驟:
建立訊號量或獲得在系統中已存在的訊號量
1). 呼叫semget().
2). 不同程序使用同乙個訊號量鍵值來獲得同個訊號量
初始化訊號量
1).使用semctl()函式的setval操作
2).當使用二維訊號量時,通常將訊號量初始化為1
3.進行訊號量pv操作
1). 呼叫semop()函式
2). 實現程序之間的同步和互斥
4.如果不需要該訊號量,從系統中刪除
1).使用semctl()函式的ipc_rmid操作
**示例:
#include
#include
#include
#include
#include
#include
#include
#define def_systemv_sem 1
union semun
;int
init_sem
(int sem_id,
int init_value)
return0;
}int
destory_sem
(int sem_id)
return0;
}int
sem_wait
(int sem_id)
return0;
}int
sem_signal
(int sem_id)
return0;
}int
main()
else
if(pid==0)
else
}
執行結果:
$ ./a.out
parent befor sleep…
parent after sleep…
child befor sleep…
child after sleep…
可以看到是父程序執行完後才執行子程序。
如果把條件編譯巨集設為0 「#define def_systemv_sem 0」
取消system v 訊號量,執行結果為
$ ./a.out
parent befor sleep…
child befor sleep…
parent after sleep…
child after sleep…
可以看到父子程序之間臨界區**執行已經亂序
通過多個訊號量解決經典的生產者—消費者的問題:
單個訊號量單單依靠乙個訊號量是無法實現的,生產者-消費者模型中,兩個程序共用臨界資源,所以它們首先互斥;此外,如果緩衝區滿,生產者是不能生產的,所以生產者程序受到消費者程序的制約;如果緩衝區空,消費者是不能消費的,所以消費者程序受到生產者程序的制約。但你用乙個訊號量去控制同步的話,因為v(n)沒有條件,所以生產者程序實際上不受制約,永不阻塞,只有消費者程序受到生產者的制約,所以,必須要用到多個訊號量,才能解決問題。
程序同步 訊號量機制
由dijkstra提出,目前已廣泛應用於單處理機和多處理機系統以及計算機網路中。一 整形訊號量 1.s 乙個用於表示資源數目的整型量 2.與一般整型量不同,除初始化外,僅能通過兩個標準的原子操作 wait s 和signal s 長期以來一直被稱為p v操作 3.wait操作偽碼描述 wait s ...
程序同步與訊號量
對於多個程序訪問共享資料,需要程序進行同步合作完成操作。我們可以使用訊號量來描述共享資料。struct semaphore p semaphore s v semaphore s 這樣的話當我們訪問共享資料時,我們可以先呼叫p操作,訪問結束後呼叫v操作,這樣就可以當成程序同步的目的。使用訊號量的問題...
程序同步與訊號量
二.訊號量臨界區保護 三.訊號量的 實現 訊號量是用來記錄可用資源或等待執行緒數目的一種特殊的整形變數。通過對訊號量的修改,使得各個程序得以有序推進,完成程序同步。訊號量的 定義 struct semaphore兩種基本操作 當程序申請消費資源時執行p函式。首先將資源數目value減一,然後判斷va...