信號量機制

信號與信號量是不同的兩種事物字支。

什么是信號量

為了防止出現(xiàn)因多個程序同時訪問一個共享資源而引發(fā)的一系列問題麸折,我們需要一種方法檐迟,它可以通過生成并使用令牌來授權卖鲤,在任一時刻只能有一個執(zhí)行進程訪問代碼的臨界區(qū)域。臨界區(qū)域是指執(zhí)行數(shù)據(jù)更新的代碼需要獨占式地執(zhí)行巍举。而信號量就可以提供這樣的一種訪問機制脆荷,讓一個臨界區(qū)同一時間只有一個進程在訪問它,也就是說信號量是用來調(diào)協(xié)進程對共享資源的訪問的懊悯。

信號量是一個特殊的變量蜓谋,程序?qū)ζ湓L問都是原子操作,且只允許對它進行等待(即P(信號變量))和發(fā)送(即V(信號變量))信息操作炭分。最簡單的信號量是只能取0和1的變量桃焕,這也是信號量最常見的一種形式,叫做二進制信號量捧毛。而可以取多個正整數(shù)的信號量被稱為通用信號量观堂。這里主要討論二進制信號量。

信號量的操作步奏如下:
P(S):
①將信號量S的值減1呀忧,即S=S-1师痕;
②如果S>=0,則該進程繼續(xù)執(zhí)行而账;否則該進程置為等待狀態(tài)胰坟,排入等待隊列。

V(S):
①將信號量S的值加1泞辐,即S=S+1笔横;
②如果S>0,則該進程繼續(xù)執(zhí)行铛碑;否則釋放隊列中第一個等待信號量的進程狠裹。

PV操作的意義:我們用信號量及PV操作來實現(xiàn)進程的同步和互斥。PV操作屬于進程的低級通信汽烦。
信號量的值與相應資源的使用情況有關涛菠。當它的值大于0時,表示當前可用資源的數(shù)量撇吞;當它的值小于0時俗冻,其絕對值表示等待使用該資源的進程個數(shù)。注意牍颈,信號量的值僅能由PV操作來改變迄薄。

Linux的信號量機制

Linux提供了一組精心設計的信號量接口來對信號進行操作,它們不只是針對二進制信號量煮岁,下面將會對這些函數(shù)進行介紹讥蔽,但請注意涣易,這些函數(shù)都是用來對成組的信號量值進行操作的。它們聲明在頭文件sys/sem.h中冶伞。

semget函數(shù)

它的作用是創(chuàng)建一個新信號量或取得一個已有信號量新症,原型為:

int semget(key_t key, int num_sems, int sem_flags);  

第一個參數(shù)key是整數(shù)值(唯一非零),不相關的進程可以通過它訪問一個信號量响禽,它代表程序可能要使用的某個資源徒爹,程序?qū)λ行盘柫康脑L問都是間接的,程序先通過調(diào)用semget函數(shù)并提供一個鍵芋类,再由系統(tǒng)生成一個相應的信號標識符(semget函數(shù)的返回值)隆嗅,只有semget函數(shù)才直接使用信號量鍵,所有其他的信號量函數(shù)使用由semget函數(shù)返回的信號量標識符侯繁。如果多個程序使用相同的key值胖喳,key將負責協(xié)調(diào)工作。
第二個參數(shù)num_sems指定需要的信號量數(shù)目巫击,它的值幾乎總是1禀晓。
第三個參數(shù)sem_flags是一組標志,當想要當信號量不存在時創(chuàng)建一個新的信號量坝锰,可以和值IPC_CREAT做按位或操作增拥。設置了IPC_CREAT標志后锭弊,即使給出的鍵是一個已有信號量的鍵,也不會產(chǎn)生錯誤错森。而IPC_CREAT | IPC_EXCL則可以創(chuàng)建一個新的确垫,唯一的信號量弓颈,如果信號量已存在,返回一個錯誤删掀。

semget函數(shù)成功返回一個相應信號標識符(非零)翔冀,失敗返回-1.

semop函數(shù)

它的作用是改變信號量的值,原型為:

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);  

sem_id是由semget返回的信號量標識符披泪,sembuf結構的定義如下:

struct sembuf{  
   short sem_num;//除非使用一組信號量纤子,否則它為0  
   short sem_op;//信號量在一次操作中需要改變的數(shù)據(jù),通常是兩個數(shù)款票,一個是-1控硼,即P(等待)操作,  
                   //一個是+1艾少,即V(發(fā)送信號)操作卡乾。  
   short sem_flg;//通常為SEM_UNDO,使操作系統(tǒng)跟蹤信號,  
                   //并在進程沒有釋放該信號量而終止時缚够,操作系統(tǒng)釋放信號量  
};  

3幔妨、semctl函數(shù)
該函數(shù)用來直接控制信號量信息鹦赎,它的原型為:

int semctl(int sem_id, int sem_num, int command, ...);  

如果有第四個參數(shù),它通常是一個union semum結構误堡,定義如下:

union semun{  
    int val;  
    struct semid_ds *buf;  
    unsigned short *arry;  
};  

前兩個參數(shù)與前面一個函數(shù)中的一樣钙姊,command通常是下面兩個值中的其中一個
SETVAL:用來把信號量初始化為一個已知的值。這個值通過union semun中的val成員設置埂伦,其作用是在信號量第一次使用前對它進行設置煞额。
IPC_RMID:用于刪除一個已經(jīng)無需繼續(xù)使用的信號量標識符。

進程使用信號量通信

下面使用一個例子來說明進程間如何使用信號量來進行通信沾谜,這個例子是兩個相同的程序同時向屏幕輸出數(shù)據(jù)膊毁,我們可以看到如何使用信號量來使兩個進程協(xié)調(diào)工作,使同一時間只有一個進程可以向屏幕輸出數(shù)據(jù)基跑。注意婚温,如果程序是第一次被調(diào)用(為了區(qū)分,第一次調(diào)用程序時帶一個要輸出到屏幕中的字符作為一個參數(shù))媳否,則需要調(diào)用set_semvalue函數(shù)初始化信號并將message字符設置為傳遞給程序的參數(shù)的第一個字符栅螟,同時第一個啟動的進程還負責信號量的刪除工作。如果不刪除信號量篱竭,它將繼續(xù)在系統(tǒng)中存在力图,即使程序已經(jīng)退出,它可能在你下次運行此程序時引發(fā)問題掺逼,而且信號量是一種有限的資源吃媒。

在main函數(shù)中調(diào)用semget來創(chuàng)建一個信號量,該函數(shù)將返回一個信號量標識符吕喘,保存于全局變量sem_id中赘那,然后以后的函數(shù)就使用這個標識符來訪問信號量。

源文件為seml.c氯质,代碼如下:

#include <unistd.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <stdlib.h>  
#include <stdio.h>  
#include <string.h>  
#include <sys/sem.h>  
  
union semun  
{  
    int val;  
    struct semid_ds *buf;  
    unsigned short *arry;  
};  
  
static int sem_id = 0;  
  
static int set_semvalue();  
static void del_semvalue();  
static int semaphore_p();  
static int semaphore_v();  
  
int main(int argc, char *argv[])  
{  
    char message = 'X';  
    int i = 0;  
  
    //創(chuàng)建信號量  
    sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);  
  
    if(argc > 1)  
    {  
        //程序第一次被調(diào)用募舟,初始化信號量  
        if(!set_semvalue())  
        {  
            fprintf(stderr, "Failed to initialize semaphore\n");  
            exit(EXIT_FAILURE);  
        }  
        //設置要輸出到屏幕中的信息,即其參數(shù)的第一個字符  
        message = argv[1][0];  
        sleep(2);  
    }  
    for(i = 0; i < 10; ++i)  
    {  
        //進入臨界區(qū)  
        if(!semaphore_p())  
            exit(EXIT_FAILURE);  
        //向屏幕中輸出數(shù)據(jù)  
        printf("%c", message);  
        //清理緩沖區(qū)闻察,然后休眠隨機時間  
        fflush(stdout);  
        sleep(rand() % 3);  
        //離開臨界區(qū)前再一次向屏幕輸出數(shù)據(jù)  
        printf("%c", message);  
        fflush(stdout);  
        //離開臨界區(qū)拱礁,休眠隨機時間后繼續(xù)循環(huán)  
        if(!semaphore_v())  
            exit(EXIT_FAILURE);  
        sleep(rand() % 2);  
    }  
  
    sleep(10);  
    printf("\n%d - finished\n", getpid());  
  
    if(argc > 1)  
    {  
        //如果程序是第一次被調(diào)用,則在退出前刪除信號量  
        sleep(3);  
        del_semvalue();  
    }  
    exit(EXIT_SUCCESS);  
}  
  
static int set_semvalue()  
{  
    //用于初始化信號量蜓陌,在使用信號量前必須這樣做  
    union semun sem_union;  
  
    sem_union.val = 1;  
    if(semctl(sem_id, 0, SETVAL, sem_union) == -1)  
        return 0;  
    return 1;  
}  
  
static void del_semvalue()  
{  
    //刪除信號量  
    union semun sem_union;  
  
    if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)  
        fprintf(stderr, "Failed to delete semaphore\n");  
}  
  
static int semaphore_p()  
{  
    //對信號量做減1操作觅彰,即等待P(sv)  
    struct sembuf sem_b;  
    sem_b.sem_num = 0;  
    sem_b.sem_op = -1;//P()  
    sem_b.sem_flg = SEM_UNDO;  
    if(semop(sem_id, &sem_b, 1) == -1)  
    {  
        fprintf(stderr, "semaphore_p failed\n");  
        return 0;  
    }  
    return 1;  
}  
  
static int semaphore_v()  
{  
    //這是一個釋放操作,它使信號量變?yōu)榭捎门ト龋窗l(fā)送信號V(sv)  
    struct sembuf sem_b;  
    sem_b.sem_num = 0;  
    sem_b.sem_op = 1;//V()  
    sem_b.sem_flg = SEM_UNDO;  
    if(semop(sem_id, &sem_b, 1) == -1)  
    {  
        fprintf(stderr, "semaphore_v failed\n");  
        return 0;  
    }  
    return 1;  
}  

運行結果如下:

![](file:///C:/Users/Administrator/AppData/Local/youdao/ynote/images/B276451808594A82A06D67B4E0C10940/QQ%E6%88%AA%E5%9B%BE20130823161426.jpg)


信號量的總結

信號量是一個特殊的變量填抬,程序?qū)ζ湓L問都是原子操作,且只允許對它進行等待(即P(信號變量))和發(fā)送(即V(信號變量))信息操作隧期。我們通常通過信號來解決多個進程對同一資源的訪問競爭的問題飒责,使在任一時刻只能有一個執(zhí)行線程訪問代碼的臨界區(qū)域赘娄,也可以說它是協(xié)調(diào)進程間的對同一資源的訪問權,也就是用于同步進程的宏蛉。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遣臼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拾并,更是在濱河造成了極大的恐慌揍堰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗅义,死亡現(xiàn)場離奇詭異屏歹,居然都是意外死亡,警方通過查閱死者的電腦和手機之碗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門蝙眶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人褪那,你說我怎么就攤上這事幽纷。” “怎么了博敬?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵友浸,是天一觀的道長。 經(jīng)常有香客問我冶忱,道長尾菇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任囚枪,我火速辦了婚禮,結果婚禮上劳淆,老公的妹妹穿的比我還像新娘链沼。我一直安慰自己,他們只是感情好沛鸵,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布括勺。 她就那樣靜靜地躺著,像睡著了一般曲掰。 火紅的嫁衣襯著肌膚如雪疾捍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天栏妖,我揣著相機與錄音乱豆,去河邊找鬼。 笑死吊趾,一個胖子當著我的面吹牛宛裕,可吹牛的內(nèi)容都是我干的瑟啃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼揩尸,長吁一口氣:“原來是場噩夢啊……” “哼蛹屿!你這毒婦竟也來了?” 一聲冷哼從身側響起岩榆,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤错负,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勇边,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體犹撒,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年粥诫,在試婚紗的時候發(fā)現(xiàn)自己被綠了油航。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡怀浆,死狀恐怖谊囚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情执赡,我是刑警寧澤镰踏,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站沙合,受9級特大地震影響奠伪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜首懈,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一绊率、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧究履,春花似錦滤否、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泥彤,卻和暖如春欲芹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吟吝。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工菱父, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓滞伟,卻偏偏與公主長得像揭鳞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子梆奈,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 信號量機構是一種功能較強的機制野崇,可用來解決互斥與同步的問題。在長期且廣泛的應用中亩钟,信號量機制得到了很大的發(fā)展乓梨。由最...
    saviochen閱讀 7,985評論 2 10
  • 信號量機制 在 iOS 系統(tǒng)及大部分現(xiàn)代操作系統(tǒng)中,多個線程可以并發(fā)執(zhí)行清酥,CPU在線程之間來回切換扶镀,共享某些資源,...
    DH_Fantasy閱讀 7,593評論 3 10
  • 進程間通信 進程間通信即IPC(InerProcess Communication)Unix ipc 已經(jīng)是而且繼...
    千里山南閱讀 454評論 0 2
  • Android跨進程通信IPC整體內(nèi)容如下 1焰轻、Android跨進程通信IPC之1——Linux基礎2臭觉、Andro...
    隔壁老李頭閱讀 15,504評論 19 113
  • 盼望已久的濱海新區(qū)文化中心 ,今天我終于去了辱志,和我們一起去的 還有阿姨和一個姐姐蝠筑,乘著出租車來到濱海新區(qū)文...
    45cbff51831c閱讀 884評論 0 1