信號量的值與相應資源的使用情況有關,當它的值大於 0 時,表示當前可用的資源數的數量;當它的值小於 0 時,其絕對值表示等待使用該資源的進程個數。信號量的值僅能由 PV 操作來改變。
- sem_op 參數:
- sem_flg 參數:
在標准操作程序中的操作是在數組的順序執行、原子的,那就是,該操作要么作為一個完整的單元,要么不。如果不是所有操作都可以立即執行的系統調用的行為取決於在個人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操作。
P操作責把當前進程由運行狀態轉換為阻塞狀態,直到另外一個進程喚醒它。操作為:申請一個空閑資源(把信號量減1),若成功,則退出;若失敗,則該進程被阻塞;
V操作負責把一個被阻塞的進程喚醒,它有一個參數表,存放着等待被喚醒的進程信息。操作為:釋放一個被占用的資源(把信號量加1),如果發現有被阻塞的進程,則選擇一個喚醒之。
semop函數原型如下:
int semop(int semid, struct sembuf *sops, unsigned nsops);
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。