訊號量實現多程序的同步訪問

2021-07-28 11:41:18 字數 4521 閱讀 2463

comm.h檔案

#ifndef _comm_h_

#define _comm_h_

#include

#include

#include

#include

#include

#include

#include

#define pathname "."

#define proj_id 06666

typedef union semun my_semun;

int creat_sems(int nsems);

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

int get_sems();

int destroy_sems(int semid,int sennum);

int p(int semid);

int v(int semid);

#endif

comm.c檔案

#include"comm.h"

static comm_sems(int nsems,int flags)

key_t key = ftok(pathname, proj_id);

int semid = semget(key,nsems,flags);

if(semid < 0)

perror("semget");

return semid;

int creat_sems(int nsems)//建立訊號量

return comm_sems(nsems,ipc_creat | ipc_excl | 0666);

int init_sems(int semid,int which,int _val)//初始化訊號量

my_semun _semun;

_semun.val = _val;

if(semctl(semid,which,setval,_semun)<0)//初始化訊號量函式

perror("init_sems");

return -1;

return 0;

int get_sems()//獲取訊號量semid

return comm_sems(0,ipc_creat);

int destroy_sems(int semid, int semnum)//銷毀訊號量

if(semctl(semid,semnum,ipc_rmid) < 0)//銷毀訊號量函式

return -1;

return 0;

static comm_semop(int semid,int which)

struct sembuf sbuf;

sbuf.sem_num = 0;

sbuf.sem_op = which;

sbuf.sem_*** = sem_undo;

if(semop(semid,&sbuf,1)<0)//訊號量操作函式

perror("semop");

return -1;

return 0;

int p(int semid)//p操作

comm_semop(semid,-1);

int v(int semid)//v操作

comm_semop(semid,1);

mysem.c檔案

#include"comm.h"

int main()//測試

int semid = creat_sems(1);//建立訊號量

init_sems(semid,0,1);//初始化訊號量

if(fork() == 0){//child

int _semid = get_sems();//子程序獲取semid

int count = 30;

while(count--){

p(_semid);//p操作

printf("a");

fflush(stdout);

usleep(231451);

printf("a");

fflush(stdout);

usleep(131451);

v(_semid);//v操作

else//father

int count = 30;

while(count--){

p(semid);//p操作

printf("b");

fflush(stdout);

usleep(131451);

printf("b");

fflush(stdout);

usleep(231451);

v(semid);//v操作

wait(null);

destroy_sems(semid,0);//刪除訊號量

//訊號量的生命週期是隨核心的

return 0;

接下來我們來編寫makefile檔案

mysem:comm.c mysem.c

gcc -o $@ $^

.phony:clean

clean:

rm -f mysem

完成上述**後讓我們來看看結果

由結果可見我們的**採用訊號量實現了多程序的同步訪問的功能,下面讓我們來深入了解一下訊號量有關的操作函式

(1)int semget(key_t key, int nsems, int sem***)

key:第乙個引數key一般是系統呼叫 key_t ftok(const char *pathname, int proj_id);

函式來獲取的具體用法可以參考上面的**.

nsems:第二個引數指出了乙個新的訊號量集中應該建立訊號量的個數

sem***:ipc_creat如果訊號量集在系統核心中不存在,則建立訊號量集。ipc_excl當和 ipc_creat一同使用時,如果訊號量集已經存在,則呼叫失敗。如果單獨使用ipc_creat,則semget()要麼返回新建立的訊號量集的識別符號,要麼返回系統中已經存在的同樣的關鍵字值的訊號量的識別符號。如果ipc_excl和ipc_creat一同使用,則要麼返回新建立的訊號量集的識別符號,要麼返回-1,所以ipc_excl和ipc_creat一同使用返回的訊號量一定是新建立的。ipc_excl單獨使用沒有意義。

返回值:成功返回semid,失敗返回-1。

(2)int semctl(int semid, int semnum, int cmd, ...)

semid:訊號量的標識碼,semget()函式的返回值

semnum:操作訊號在訊號集中的編號,第乙個訊號量的編號為0

ipc_stat讀取乙個訊號量集的資料結構semid_ds,並將其儲存在semun中的buf引數中。

ipc_set設定訊號量集的資料結構semid_ds中的元素ipc_perm,其值取自semun中的buf引數。

ipc_rmid將訊號量集從記憶體中刪除。

getall用於讀取訊號量集中的所有訊號量的值。

getncnt返回正在等待資源的程序數目。

getpid返回最後乙個執行semop操作的程序的pid。

getval返回訊號量集中的乙個單個的訊號量的值。

getzcnt返回這在等待完全空閒的資源的程序數目。

setall設定訊號量集中的所有的訊號量的值。

setval設定訊號量集中的乙個單獨的訊號量的值。

上述**中我們採用semctl()函式刪除了訊號量以及初始化。

採用semctl刪除訊號量我們只需將ipc_rmid引數傳遞給cmd。

採用semctl初始化訊號量時第三個引數需要設定為setval;此時還需要第四個引數union semun,具體用法可以參看上面的**。

返回值:成功返回0,失敗返回-1.

(3)int semop(int semid, struct sembuf *sops, unsigned nsops)

semid:訊號量的標識碼

sops:sops是乙個指向結構體陣列的指標。

struct   sembuf{

unsigned short  sem_num;//第幾個訊號量,第乙個訊號量為0;

short  sem_op;//對該訊號量的操作。

short _sem***;

_sem***:訊號操作標誌,可能的選擇有兩種

ipc_nowait // 對訊號的操作不能滿足時, semop() 不會阻塞,並立即返回,同時設定錯誤資訊。

sem_undo // 程式結束時 ( 不論正常或不正常 ) ,保證訊號值會被重設為 semop() 呼叫前的值。這樣做的目的在於避免程式在異常情況下結束時未將鎖定的資源解鎖, 造成該資源永遠鎖定。

nsops:操作結構的數量,恆大於或等於1

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

這三個函式的標頭檔案為:

#include

#include

#include

linux 訊號量 同步多程序

訊號量集函式 include include include semget函式 功能 用來建立和訪問乙個訊號量集 原型int semget key t key,int nsems,int sem 引數key 訊號集的名字 nsems 訊號集中訊號量的個數 sem 由九個許可權標誌構成,它們的用法和建...

System V訊號量 多程序同步

1.概述 systemv訊號量並不如posix訊號量那樣 好用 但相比之下它的年代更加久遠,但是systemv使用的卻更加廣泛 尤其是在老系統中 在學習posix訊號量的時候,已經大概清楚了二值訊號量和計數訊號量是什麼東西。在接觸systemv訊號量之後,這裡有乙個新的概念叫做 計數訊號量集。其實就...

同步 訊號量

include stdafx.h include includeusing namespace std int number 1 定義全域性變數 handle hsemaphore 定義訊號量控制代碼 unsigned long stdcall threadproc1 void lp long co...