信號量的值與相應資源的使用狀況有關,當它的值大於 0 時,表示當前可用的資源數的數量;當它的值小於 0 時,其絕對值表示等待使用該資源的進程個數。信號量的值僅能由 PV 操做來改變。linux
在標準操做程序中的操做是在數組的順序執行、原子的,那就是,該操做要麼做爲一個完整的單元,要麼不。若是不是全部操做均可以當即執行的系統調用的行爲取決於在我的sem_flg領域的IPC_NOWAIT標誌的存在。
------------------------------------------------------------------------------------------------- 數組
T&T的貝爾實驗室,對Unix早期的進程間通訊進行了改進和擴充,造成了"system V IPC",其通訊進程主要侷限在單個計算機內。IPC對象指的是共享內存(share memory)、消息隊列(message queue)和信號燈集(semaphore)。數據結構
信號燈(semaphore),也叫信號量。它是不一樣進程間或一個給定進程內部不一樣線程間同步的機制。System V的信號燈是一個或者多個信號燈的一個集合。其中的每個都是單獨的計數信號燈。System V 信號燈由內核維護。主要函數semget,semop,semctl。函數
本文重點介紹的是semop函數。該函數主要功能是對信號燈進行P/V操做。post
P操做責把當前進程由運行狀態轉換爲阻塞狀態,直到另一個進程喚醒它。操做爲:申請一個空閒資源(把信號量減1),若成功,則退出;若失敗,則該進程被阻塞;spa
V操做負責把一個被阻塞的進程喚醒,它有一個參數表,存放着等待被喚醒的進程信息。操做爲:釋放一個被佔用的資源(把信號量加1),若是發現有被阻塞的進程,則選擇一個喚醒之。操作系統
semop函數原型以下:線程
int semop(int semid, struct sembuf *sops, unsigned nsops);xml
semop操做中:sembuf結構的sem_flg成員能夠爲0、IPC_NOWAIT、SEM_UNDO 。爲SEM_UNDO時,它將使操做系統跟蹤當前進程對這個信號量的修改狀況,若是這個進程在沒有釋放該信號量的狀況下終止,操做系統將自動釋放該進程持有的。對象
sembuf結構的sem_flg成員爲SEM_UNDO時,它將使操做系統跟蹤當前進程對這個信號量的修改狀況,若是這個進程在沒有釋放該信號量的狀況下終止,操做系統將自動釋放該進程持有的信號量
問題描述:假設父子進程對一個文件進行寫操做,可是這個文件同一時間只能有一個進程進行寫操做。
示例程序以下:
#include <stdio.h>
//……此處省略了頭文件
void P(int sid)
{
struct sembuf sem_p;
sem_p.sem_num = 0;
sem_p.sem_op = -1;
sem_p.sem_flg = 0;
if (semop(sid, &sem_p, 1) == -1)
{
perror("p op failed");
exit(1);
}
}
void V(int sid)
{
struct sembuf sem_p;
sem_p.sem_num = 0;
sem_p.sem_op = 1;
//sem_p.sem_flg = SEM_UNDO;
sem_p.sem_flg = 0;
if (semop(sid, &sem_p, 1) == -1)
{
perror("v op failed");
exit(1);
}
}
int main(int argc, char * argv[ ])
{
pid_t pid;
int fd;
key_t key;
int sid;
if ((fd = open("semset", O_RDWR | O_CREAT, 0666)) == -1)
{
perror("open");
exit( -1);
}
if ((key=ftok("semset", 'a')) == -1)
{
perror("ftok");
return -1;
}
if ((sid = semget(key, 1, IPC_CREAT | 0666)) == -1)
{
perror("createSemset");
exit(-1);
}
if( -1==semctl(sid, 0, SETVAL, 1) )
{
perror("SETVAL");
exit(1);
}
if ((pid=fork()) == -1)
{
perror("fork");
exit(-1);
}
else if ( 0 == pid )
{
while(1)
{
P(sid);
printf("child writing\n");
sleep(1);
printf("child finish post\n");
V(sid);
}
}
else
{
while(1)
{
P(sid);
printf("parent writing");
sleep(1);
printf("parent writing finish post\n");
V(sid);
}
}
return 0;
}
在該程序中,父子進程都有可能執行P操做成功,所以,兩個進程中的提示語句,交替顯示。若經過kill命令把其中一個進程殺死,且該進程尚未執行V操做釋放資源。若使用SEM_UNDO標誌,則操做系統將自動釋放該進程持有的信號量,從而使得另一個進程能夠繼續工做。若沒有這個標誌,另外進程將P操做永遠阻塞。
所以,通常建議使用SEM_UNDo標誌。
=================================================
IPC_NOWAIT:當指定的操做不能完成時,進程不等待當即返回,返回值爲-1,errno置爲EAGAIN。