程序間通訊(4) 訊號量

2021-08-17 12:15:49 字數 4467 閱讀 8422

之前我們學習了管道,訊息佇列,共享記憶體,今天我們再來學一種程序間通訊的方式-----訊號量

訊號量

兩個程序看到的同乙個公共的資源,但是同時只能被乙個程序所使用的的資源叫做臨界資源(互斥資源)

在晉城中涉及到互斥資源的程式段叫臨界區

互斥:

各個程序都要訪問共享資源,但共享資源是互斥的,同時只能有乙個程序使用。因此,各個程序之間競爭使用這些資源,將這種關係稱為互斥。

同步:

多個程序需要相互配合共同完成一項任務。

訊號量的工作機制

簡單說一下訊號量的

工作機制

,可以直接理解成計數器

,訊號量會有初值(>0)

,每當有程序申請使用訊號量,通過乙個p操作來對訊號量進行-1操作

,當計數

器減到0的時候就說明沒有資源了,其他程序要想訪問就必須等待

,當該程序執行完這段工作(我們稱之為臨界區)之後,就會執行v操作來對訊號量進行+1操作。

由於訊號量只能進行兩種操作等待和傳送訊號,即pv,他們的行為是這樣的:(程序共享訊號量sv)

p:如果sv的值大於零,就給它減1;如果它的值為零,就掛起該程序的執行

struct semaphore

p原語

p(s)

}

v原語

v(s)

}

訊號量集結構

struct semid_ds ;
訊號量集函式semget函式功能:⽤用來建立和訪問⼀乙個訊號量集

原型

int semget(key_t key, int nsems, int sem***);
引數

key: 訊號集的名字

nsems:訊號集中訊號量的個數

sem***: 由九個許可權標誌構成,它們的⽤法和建立⽂件時使用的mode模式標誌是⼀樣的

ipc_creat|ipc_excl:不存在建立,存在出錯返回

ipc_creat:不存在建立,存在返回

返回值:成功返回⼀個⾮負整數,即該訊號集的標識碼;失敗返回-1

shmctl函式

功能:⽤用於控制訊號量集

原型

int semctl(int semid, int semnum, int cmd, ...);
引數

semid:由semget返回的訊號集標識碼

semnum:訊號集中訊號量的序號

cmd:將要採取的動作(有三個可取值)最後乙個引數根據命令不同⽽不同

返回值:成功返回0;失敗返回-1

命令說明

setval

設定訊號量集中的訊號量的計數值

cetval

獲取訊號量集中的訊號量的計數值

ipc_stat

把semid_ds結構中的資料設定為訊號集的當前關聯值

ipc_set

在程序由足夠許可權的前提下,把訊號集的當前關聯值設定為semid_ds資料結構中給出的值

ipc_rmid

刪除訊號集

semop函式

功能:⽤來建立和訪問⼀個訊號量集

原型

int semop(int semid, struct sembuf *sops, unsigned nsops);
引數

semid:是該訊號量的標識碼,也就是semget函式的返回值

sops:是個指向⼀個結構數值的指標

nsops:訊號量的個數

返回值:成功返回0;失敗返回-1

sembuf定義如下:

struct sembuf;
訊號量操作步驟:一、建立或獲取乙個訊號量,呼叫semget()函式。

二、初始化訊號量,呼叫semctl()。

三、進行訊號量的pv操作,呼叫semop()函式。

四、訊號退出時,從系統中刪除該訊號,呼叫semctl(),ipc_rmid操作。

接下來我們用訊號量來實現兩個程序間的通訊:

**如下:

comm.h

#ifndef __comm_h__

#define __comm_h__

#include #include #include #include #include #include #define pathname "."

#define proj_id 0

union semun

;//訊號量是建立還是獲取在於semget函式引數flag的設定

static int commsemid(int nums, int flags);

//建立訊號量

int creatsemid(int nums);

//獲取已經建立的訊號量

int getsemid(int nums);

//初始化訊號量

int initsem(int semid, int which, int _val);

//pv操作在於它_op的值

static int sempv(int semid, int which, int _op);

//p操作

int p(int semid, int which, int _op);

//v操作

int v(int semid, int which, int _op);

//由於(system v通訊方式)訊號量生命週期隨核心,所以要銷毀訊號量

int destory(int semid);

#endif

comm.c

#include "comm.h"

static int commsemid(int nums, int flags)

else }

int creatsemid(int nums)

int getsemid(int nums)

int destory(int semid)

else }

int initsem(int semid, int which, int _val)

return 0;

}static int sempv(int semid, int which, int _op)

int p(int semid, int which, int _op)

return 0;

}int v(int semid, int which, int _op)

return 0;

}

test_sem.c

#include "comm.h"

int main()

}else

if (waitpid(id, null, 0) < 0)

}destory(semid);

return 0;

}

makefile

test_sem:comm.c test_sem.c

gcc -o $@ $^

.phony:clean

clean:

rm -f test_sem

此時顯示器只有乙個,兩個程序同時列印,此時顯示器成為臨界資源,使用二元訊號量(互斥鎖)進行保護。

我們在執行結果前,可以使用ipcs -s 命令檢視訊號進行程序間通訊的資訊。

可以看出,此時並沒有資訊。

我們現在來執行**,結果如下:

我們可以看到所有的ab都是成對出現的,不會出現交叉的情況。這是因為p、v操作實現過程中具有原子性,能夠實現對臨界區

的管理,

但是如果我們不加p、v操作,那麼會出現什麼樣的情況呢??我們來看一下:

**修改後,執行結果如下:

我們可以發現,螢幕上輸出的ab出現交叉,並沒有成對列印。

程序間通訊 訊號量

ipc識別符號和關鍵字 在終端輸入ipcs,可以看到目前系統中所有的ipc資訊 第一列的key就是ipc的關鍵字,第二列是ipc的識別符號。ftok 函式用於獲得乙個ipc的關鍵字,其函式原型是 key t ftok const char pathname,int proj id 下面是乙個訊號量的...

程序間通訊 訊號量

system ipc中,對於每乙個新建的訊號量 訊息佇列 共享記憶體,都有乙個在整個系統中唯一的識別符號。每個標識也都有唯一對應的關鍵字,關鍵字的資料型別為ket t 在終端輸入命令 ipcs 可以看到目前系統中所有的ipc資訊 共享記憶體段 鍵 shmid 擁有者 許可權 位元組 nattch 狀...

程序間通訊 訊號量

訊號量不是ipc 機構,它只是乙個計數器用於不同程序之間或同一程序不同執行緒之間的同步,型別 二元訊號 值為0或 1,1說明有可用資源,0說明此時資源占用,其他程序需等待。計數訊號量 表示可用資源數量。計數訊號量集 由乙個或多個訊號量組成的集合,每乙個都是計數訊號量。訊號量資料結構 include ...