您好,登錄后才能下訂單哦!
進程間通信-信號量
1、為什么要使用信號量
為了防止多個程序同時訪問一個共享資源而引發的一系列問題,故有這樣一種方法,在任何一個時刻只有一個執行線程訪問代碼的臨界區(臨界區是指訪問臨界資源的代碼),而信號量就可以提供這樣的訪問機制,同一時刻只允許一個線程訪問臨界區,也就是說信號量是用來協調進程共享資源訪問的,也就是說信號量用來協調進程對共享資源訪問的,其中共享內存就是用信號量實現的。
2、信號量的工作原理
由于信號量只能進行兩種操作等待和發送信號,他們是p(sv)操作,v(sv)操作。
p(sv)操作:如果sv的值大于0.他就減1,如果sv的值等于0,它就掛起進程的執行。
v(sv)操作:如果有其他進程因等待sv而掛起,則就讓他恢復運行,如果沒有進程因等待它而掛起,就讓他加1.
舉個例子,就是 兩個進程共享信號量sv,一旦其中一個進程執行了P(sv)操作,它將得到信號量,并可以進入臨界區,使sv減1。而第二個進程將被阻止進入臨界區,因為 當它試圖執行P(sv)時,sv為0,它會被掛起以等待第一個進程離開臨界區域并執行V(sv)釋放信號量,這時第二個進程就可以恢復執行。
3、Linux信號量機制
Linux提供了一組精心設置的信號量接口來對信號量進行操作。這些函數都是用來對組的信號量進行操作,他們被聲明在sys/sem.h中。
4、信號量的使用
(1)創建信號量
semget函數創建一個信號量集或者訪問一個已存在的信號量集
int semget (key_t key, int nsem, int oflag)
返回值是一個稱為信號量標識符的整數,semop和semctl函數將使用它。成功返回信號量的標示符,失敗返回-1
key:由ftok()函數得到,
nsem:創建信號量中的個數
oflag:
IPC_CREAT:若內核中不存在鍵值與key相等的信號量集,則創建,否則,返回此信號量集的標識符
IPC_EXCL:單獨使用無意義
IPC_CREAT | IPC_EXCL :創建一個新的信號量集并返回信號量集的標識符,否則,返回-1.
(2)打開信號量(完成對信號量的PV操作)
用semget打開一個信號量后,對其中一個或多個信號量操作就是用semop來執行。
int semop (int semid, struct sembuf * opsptr, size_t nops)
semid:信號量集標識符
nsops:進行操作信號量的個數,即sops結構變量的個數,需大于或等于1.
opspt:是一個指針,它指向一個信號量操作數組,信號量操作由sembuf結構表示
struct sembuf{ short sem_num; // 除非使用一組信號量,否則它為0 short sem_op; // 信號量在一次操作中需要改變的數據,通常是兩個數, // 一個是-1,即P(等待)操作,一個是+1,即V(發送信號)操作 short sem_flg; // 通常為SEM_UNDO,使操作系統跟蹤信號,并在進程沒有釋放該信號量而終止時, // 操作系統釋放信號量 };
當操作信號量(semop)時,flg可以設置SEM_UNDO標識;SEM_UNDO用于將修改的信號量值在進程正常退出(調用exit退出或main執行完)或異常退出(如段異常、除0異常、收到KILL信號等)時歸還給信號量。進程以SEM_UNDO方式操作后;在進程未退出時,可以改變信號量的值,在進程退出時,將修改的值歸還給信號量,信號量變成原來的值。
(3)在指定信號集或者信號集上的某個信號進行操作
int semctl(int semid,int semnum,int cmd,union semun arg)
semid: 信號量集標識符
semnum:信號量集數組上的下標,表示某一個信號量
第四個參數是可選的,取決于第個信號(操作對象)
參數cmd指定以下10種命令中的一種,在semid指定的信號量集合上執行此命令。
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 設置信號量集中的一個單獨的信號量的值。
5.例子
comm.h
#define _PATH_NAME_ "/tmp" #define _PROJ_ID_ 0x6666 int create_sem_set(); union semun { int val; struct semid_ds* buf; unsigned short *array; struct eminfo*_buf; }; int init_sem_set(int sem_id,int which,int val); int create_sem_set(int nums); int get_sem_set(); int destory_sem_set(int sem_id); int P(int sem_id,int num); int V(int sem_id,int num);
comm.c
#include"comm.h" static int comm_sem_set(int nums,int flags) { key_t _key = ftok(_PATH_NAME_,_PROJ_ID_); if(_key<0) { perror("ftok"); return -1; } // int sem_id = semget(_key,nums,IPC_CREAT |IPC_EXCL); int sem_id = semget(_key,nums,flags); if(sem_id <0) { perror("semget"); return -2; } return sem_id; } int create_sem_set(int nums) { int flags = IPC_CREAT | IPC_EXCL | 0666; return comm_sem_set(nums,flags); } int get_sem_set() { int flags = IPC_CREAT; return comm_sem_set(0,flags); } int destory_sem_set(int sem_id) { if(semctl(sem_id,0,IPC_RMID)<0) { perror("semctl"); } return 0; } int init_sem_set(int sem_id,int which,int val) { union semun _un; _un.val = val; if(semctl(sem_id,which,SETVAL,_un)<0) { perror("semctl"); return -1; } } static int comm_op(int sem_id,int num,int op) { struct sembuf _sembuf; _sembuf.sem_num = num; _sembuf.sem_op = op; _sembuf.sem_flg = 0; if(semop(sem_id,&_sembuf,1)<0) { perror("semop"); return -1; } return 0; } int P(int sem_id,int num) { int op = -1; return comm_op(sem_id,num,op); } int V(int sem_id,int num) { int op = -1; return comm_op(sem_id,num,op); }
test_sem.c
#include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> #define _PATH_NAME_ "/tmp" #define _PROJ_ID_ 0x6666 int create_sem_set(); union semun { int val; struct semid_ds* buf; unsigned short *array; struct eminfo*_buf; }; int init_sem_set(int sem_id,int which,int val); int create_sem_set(int nums); int get_sem_set(); int destory_sem_set(int sem_id); int P(int sem_id,int num); int V(int sem_id,int num); [lh@localhost SEM]$ ^C [lh@localhost SEM]$ cat comm.c #include"comm.h" static int comm_sem_set(int nums,int flags) { key_t _key = ftok(_PATH_NAME_,_PROJ_ID_); if(_key<0) { perror("ftok"); return -1; } // int sem_id = semget(_key,nums,IPC_CREAT |IPC_EXCL); int sem_id = semget(_key,nums,flags); if(sem_id <0) { perror("semget"); return -2; } return sem_id; } int create_sem_set(int nums) { int flags = IPC_CREAT | IPC_EXCL | 0666; return comm_sem_set(nums,flags); } int get_sem_set() { int flags = IPC_CREAT; return comm_sem_set(0,flags); } int destory_sem_set(int sem_id) { if(semctl(sem_id,0,IPC_RMID)<0) { perror("semctl"); } return 0; } int init_sem_set(int sem_id,int which,int val) { union semun _un; _un.val = val; if(semctl(sem_id,which,SETVAL,_un)<0) { perror("semctl"); return -1; } } static int comm_op(int sem_id,int num,int op) { struct sembuf _sembuf; _sembuf.sem_num = num; _sembuf.sem_op = op; _sembuf.sem_flg = 0; if(semop(sem_id,&_sembuf,1)<0) { perror("semop"); return -1; } return 0; } int P(int sem_id,int num) { int op = -1; return comm_op(sem_id,num,op); } int V(int sem_id,int num) { int op = -1; return comm_op(sem_id,num,op); } [lh@localhost SEM]$ ^C [lh@localhost SEM]$ clear [lh@localhost SEM]$ cat test_sem.c #include"comm.h" #include<stdio.h> int main() { int sem_id = create_sem_set(1); pid_t id = fork(); init_sem_set(sem_id,0,1); if(id ==0) { int sem_id_child = get_sem_set(); while(1) { P(sem_id_child,0); printf("A"); fflush(stdout); usleep(rand()%3); printf("A"); fflush(stdout); usleep(rand()%12345); V(sem_id_child,0); } } else { while(1) { P(sem_id,0); printf("B"); fflush(stdout); usleep(rand()%3); printf("B"); fflush(stdout); usleep(rand()%12234); V(sem_id,0); } wait(NULL); destory_sem_set(sem_id); } return 0; }
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。