程序通訊之訊號量
一、引言:
我們知道在一條單軌鐵路上,任何時候在上面只能有一列列車行駛在上面。而管理這條鐵路的系統就是訊號量,任何一列列車必須等到表明可以行駛的訊號確認以後才能進入鐵路。當一列列車進入軌道行駛時,需要將軌道改為禁止其他列車進入,從而防止不知情的列車進入軌道,發生衝突。而當列車行駛完這條軌道後,需要將軌道改回原來允許其他列車進入這個軌道。這也可以用交通手勢來形象化舉例。那麼這個訊號量到底是什麼,它的工作是怎麼處理,以及如何運用呢。
二、訊號量的理論以及相關知識
訊號量在計算機上實際是乙個簡單的整數,那麼這個的整數的作用以及意義是什麼呢?
訊號量就是乙個計數器,是記錄一塊臨界資源能同時被幾個程序訪問的計數器。比如乙個停車場有2個空閒的停車位,這時候來了三輛車,當停車場的管理員允許一輛車通過時,這時候,車位就變成了乙個,當最後剩下了一輛車時,停車位滿了,那麼這時候管理員舉會讓著輛車等待,直到有一輛車離開為止,剩下的這輛車才能進去。這裡的管理員相當於就是訊號量,用來通知車輛的進入和車輛的離開。
上面我們提到臨界資源,那麼臨界資源到底是什麼呢?
臨界資源:多道程式系統中有許多的程序,而這些程序共享著各種資源,但是有很多資源一次只能供乙個程序使用。所以在同一時刻,只能供乙個程序使用的資源就叫臨界資源,比如現實中的印表機。而程序之間採取互斥的方式共享這些資源。比如軟體中的:陣列,變數,緩衝區等等也是臨界資源。
臨界區:每個程序中訪問臨界資源的**區域就是臨界區;
原子操作:眾所周知,原子原本是指的是不可再分的最小顆粒,所以原子操作就是不能被分割的指令,原子操作可以保證指令以原子的方式執行,這樣執行過程則不會被打斷中止,直到指令結束為止。在單處理器上,操作一旦進行執行,則不能停止,直到執行完畢。在多處理器上,操作執行時,其操作中的變數將被鎖住,防止其他的程序訪問,直到操作執行完畢。
程序同步執行:程序之間存在著相互協作的能力,而程序的同步執行就是一種協作的關係,當乙個程序的執行觸發了某些條件使得另外乙個程序執行的過程叫做同步執行。(當乙個程序傳送出資訊後,接受者才能接受到資訊)
比如當程序a向緩衝區寫入資料,供給程序b使用,這時候如果緩衝區空了,而程序b執行,則程序b會被阻塞,直到程序a 向緩衝區寫資料。反之當緩衝區滿了,程序a將會被阻塞,直到程序b從緩衝區讀資料,程序a才會被喚醒。
如圖**:
程序非同步執行:就是當乙個非同步呼叫過程發出後,呼叫者不能立即得到結果,在完成後通知呼叫者結果,這與程序同步執行相對。也就是兩個程序互不干涉,不影響自身的執行。
程序同步與非同步的區別形象化:
程序同步:就是給了小狗乙個漢堡,看著小狗把漢堡吃完,走過來對你舔一舔,搖一搖尾巴,這就是程序同步。
程序非同步:就是給了小狗乙個漢堡吃,然後就走開了,等過一段時間以後小狗去找你給你說漢堡肉少了,不好吃,這就是程序非同步,你和小狗之間各幹各的互不干擾。
我們說過訊號量是程序之間通訊的一種方式,其實不光如此,程序更是一種同步機制,使得更好的去完成程序的同步執行。
三、訊號量的操作以及包含元素
訊號量集:訊號量的乙個集合,也就是乙個陣列。
其實訊號量是以集合的形式建立的,乙個訊號量有乙個或多個訊號量。
乙個訊號量包含以下元素:
訊號量的當前值
在訊號量上操作的最後乙個程序的pid
等待該訊號量的值大於訊號量的當前值的程序數
等待該訊號量為0的程序數
系統提供的操作訊號量的系統api:
由於訊號量是在作業系統核心實現的,所以需要呼叫系統提供的函式,然後自己進行封裝。
訊號量函式定義如下:
semget函式:建立乙個新訊號量或者取得乙個已有訊號量的鍵
int semget(key_t key, int num_sems, int sem_flags);
第乙個引數key是整數值,不相關的程序可以通過它訪問同乙個訊號量。程式對所有的訊號量訪問都是間接的,它先提供乙個鍵,再由系統生成相應的訊號量識別符號。只有semget函式才能直接使用訊號量鍵,其他的訊號量函式都是使用semget函式的返回的訊號量識別符號。
num_sems引數是指定需要的訊號量數目。
sem_flags引數是一組標誌,它與open函式的標誌非常類似,它低端的9個位元是該訊號量的許可權,類似於檔案訪問許可權。sem_flags包括:ipc_creat和ipc_excl。
操作許可權:onnn
ipc_creat:建立乙個新的訊號量
ipc_excl:建立出來的是乙個新的、唯一的訊號量。
返回值:成功返回乙個正數(非零值),其他訊號量函式的訊號量的識別符號
如果失敗,則返回-1.
semop函式:用於改變訊號量的值
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
第乙個引數:sem_id是semget函式返回的訊號量識別符號;
第二個引數:sem_ops是乙個指向結構陣列的指標。
結構體定義如下:
struct sembuf
第乙個成員sem_num是訊號量標號,除非你需要使用一組訊號量,否則它取值一般為0;
第二個成員sem_op是訊號量的p v 操作
第三個成員sem_***通常設定為sem_undo,它使得作業系統跟蹤當前程序對這個訊號量的修改,當程序退出時取消正在執行的pv操作。
第三個引數num_sem_ops是sem_op陣列的元素個數。
返回值:成功返回0,失敗返回-1;
semctl函式:用來控制訊號量的資訊
int semctl(int sem_id, int sem_num,int command,···);
第乙個引數:sem_id是semget函式返回的訊號量識別符號;
第二個引數sem_num是訊號量標號,一般取值為0,表示這是第乙個也是唯一的乙個訊號量;
第三個引數command是將要採取的動作。
如果還有第四個引數,它將會是乙個union semun結構,由程式設計師自己定義
union semun
訊號量操作:
建立(初始化) 或者 是獲取
p操作 :-1 阻塞執行
v操作 :+1 釋放資源
刪除對訊號量的操作的封裝:
void sem_get() // 建立並初始化 或者獲取
void sem_p() //p操作
void sem_v() //v操作
void sem_del() //刪除
封裝**實現如下:
標頭檔案:
sem.h檔案
#ifndef __sem_h
#define __sem_h
#include #include #include #include #include #include int semid;
union sembuff
;void sem_get();
void sem_p();
void sem_v();
void sem_del();
#endif
函式實現:
sem.c 檔案
#include "sem.h"
void sem_get()
//完成初始化
union sembuff data;
data.val = 1;
semctl(semid,0,setval,data); }}
void sem_p()
void sem_v()
void sem_del()
四、練習
a 程序接受使用者輸入, 當使用者輸入為「baby」 時, b 程序開始計算 100 以內所有的素
數, 假設 b 程序執行時間需要 5 秒。 a 在這 5 秒內不能接受使用者輸入。
linux終端下:gcc編譯命令為:
a.c檔案:gcc -o a a.c sem.c
b.c檔案:gcc -o b b.c sem.c
**如下:
a.c檔案
#include #include #include #include #include #include "sem.h"
void main()
; printf("請輸入正確口令:\n");
fflush(stdout);
fgets(buff,127,stdin);
if (strncmp(buff,"baby",4) == 0)
}exit(0);
}
b.c檔案
#include #include #include #include #include #include "sem.h"
#define max 100
void main()
{ sem_get();
sem_p();
while(1)
{ int i = 1;
int j = 1;
for (; i結果如下:
程序通訊之訊號量
1 訊號和訊號量 訊號與訊號量是不同的兩種事物。訊號量是用來調協程序對共享資源的訪問的。為了防止出現因多個程式同時訪問乙個共享資源而引發的一系列問 題,通過生成並使用令牌來授權,在任一時刻只能有乙個執行執行緒訪問 的臨界區域。臨界區域是指執行資料更新的 需要獨佔式地執行,而訊號量就可以提供這樣的一種...
程序通訊之訊號量
一 訊號量 訊號燈 概念 訊號量提供一種訪問機制,讓乙個臨界區同一時間只有乙個程序在訪問他,也就是說訊號量用來協調程序對共享資源的訪問的。訊號量是乙個特殊的變數,程式對其訪問都是原子操作,只允許對他進行等待 p 和傳送資訊 v 的操作。最簡單的訊號量只能取0和1的變數,這也是訊號量最常見的一種形式,...
程序通訊之訊號量
訊號量 訊號量是乙個計數器,用來表示系統資源的數量,訊號量用於多程序對共享資料物件的訪問,來實現程式的同步互斥。為了正確實現訊號量,訊號量的加減操作必須是原子操作,因此,訊號量也是在核心中實現的。先看一下同步互斥和原子操作 同步互斥 互斥 乙個程序占用資源,其它程序就不能使用該資源,程序間的這種關係...