进程间通信——信号量及ipcs/ipcrm 介绍
1.信號量描述
信號量是用來同步進程的(即控制進程的執(zhí)行),是一個特殊的變量,一般取正數(shù)值。它的值代表允許訪問的資源數(shù)目。獲取資源時,需要對信號量的值進行原子減一,該操作被稱為 P 操作。當(dāng)信號量值為 0 時,代表沒有資源可用,P 操作會阻塞。釋放資源時,需要對信號量的值進行原子加一,該操作被稱為 V操作。信號量主要用來同步進程。信號量的值如果只取 0,1,將其稱為二值信號量。如果信號量的值大于 1,則稱之為計數(shù)信號量。
臨界資源:同一時刻,只允許被一個進程或線程訪問的資源
臨界區(qū):訪問臨界資源的代碼段
2.信號量使用
2.1操作信號量的接口介紹:
#include <sys/sem.h> #include <sys/types.h> #include <sys/ipc.h> /* semget()創(chuàng)建或者獲取已存在的信號量 semget()成功返回信號量的 ID, 失敗返回-1 key:兩個進程使用相同的 key 值,就可以使用同一個信號量 nsems:內(nèi)核維護的是一個信號量集,在新建信號量時,其指定信號量集中信號量的個數(shù) semflg 可選: IPC_CREAT IPC_EXCL */ int semget(key_t key, int nsems, int semflg);/* semop()對信號量進行改變,做 P 操作或者 V 操作 semop()成功返回 0,失敗返回-1 nsops是信號量個數(shù) struct sembuf {unsigned short sem_num; //指定信號量集中的信號量下標short sem_op; //其值為-1,代表 P 操作,其值為 1,代表 V 操作short sem_flg; //SEM_UNDO }; */ int semop( int semid, struct sembuf *sops, unsigned nsops);/* semctl()控制信號量 semctl()成功返回 0,失敗返回-1 cmd 選項: SETVAL //將val的值同步到信號量上IPC_RMID union semun//信號量下標 {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf; }; */ int semctl( int semid, int semnum, int cmd, ...);2.2封裝信號量的接口:
sem.h 的代碼如下:
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<assert.h> #include<sys/sem.h>union semu{int val};void sem_init();//創(chuàng)建并初始化,或者獲取已有的信號量id void sem_p();//p操作,信號量減一 void sem_v();//v操作,信號量加一 void sem_destroy();//銷毀信號量sem.c代碼如下:
#include"sem.h"static int semid = -1;void sem_init() {semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);if(semid == -1)//信號量已經(jīng)存在{semid = semget((key_t)1234,1,0600);}else//信號量不存在,信號量被創(chuàng)建,在這里初始化信號量{union semun a;a.val = 1;if(semctl(semid,0,SETVAL,a)==-1){perror("semctl error");}} }void sem_p() {struct sembuf buf;buf.sem_num = 0;buf.sem_op = -1;//Pbuf.sem_flg = SEM_UNDO;if(semop(semid,&buf,1)==-1){perror("semop P error");} }void sem_v() {struct sembuf buf;buf.sem_num = 0;buf.sem_op = 1;//Vbuf.sem_flg = SEM_UNDO;if(semop(semid,&buf,1)==-1){perror("semop V error");} }void sem_destroy() {if(semctl(semid,0,IPC_RMID) == -1){perror("semtcl del error");} }記不住怎么封裝的也沒關(guān)系,一般我們使用時,都是封裝好的,我們只要知道怎么用信號量PV操作控制進程就好。
2.3例題演示:
例題(1):進程 a 和進程 b 模擬訪問打印機,進程 a 輸出第一個字符‘a(chǎn)’表示開始使用打印機,輸出第二個字符‘a(chǎn)’表示結(jié)束使用,b 進程操作與 a 進程相同。(由于打印機同一時刻只能被一個進程使用,所以輸出結(jié)果不應(yīng)該出現(xiàn) abab),如圖所示:
a.c代碼如下:
a.c最后sleep(10)是為了使a程序最后結(jié)束,這樣可以在a程序里銷毀信號量。
b.c代碼:
運行結(jié)果:
可以發(fā)現(xiàn),由于打印機要求只有一個,所以a使用完打印機,b或者a才能繼續(xù)使用打印機,不可能a和b同時使用打印機的。
(2)例題2:有一個空間,要求A進程先向里面寫數(shù)據(jù),B進程再從里面讀數(shù)據(jù),然后A進程再寫…
分析1:一個信號量情況如下:
一眼看去發(fā)現(xiàn)沒什么問題,但是仔細思考發(fā)現(xiàn)并沒有對A寫入數(shù)據(jù)進行控制,A寫入數(shù)據(jù)不受信號量控制,A寫完仍可以寫。我們要求是A寫完之后,B讀完,A才可以再次寫入的。
所以不可行。
分析2:兩個信號量:
一個信號量限制A寫入,一個信號量限制B讀取
如下圖:
3.ipcs/ipcrm 介紹
ipcs 可以查看消息隊列、共享內(nèi)存、信號量的使用情況,使用 ipcrm 可以進行刪除操作。
如果我們將a.c程序中的銷毀信號量的操作去掉,那么我們創(chuàng)建的信號量就沒有銷毀。a.c代碼如下。
運行完a和b程序后,由于程序里沒有對信號量進行銷毀,所以我們創(chuàng)建的信號量仍然存在。可以用指令ipcs查看。
以下是運行完a和b程序后用指令ipcs查看的信號量信息:
key值是16進制,換成10進制,就是我們程序中設(shè)置的key值1234。
可以用指令ipcrm + -s + semid指令銷毀信號量。
ipcrm -m是對共享內(nèi)存用的;
ipcrm -q是對消息隊列弄的;
總結(jié)
以上是生活随笔為你收集整理的进程间通信——信号量及ipcs/ipcrm 介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 进程间通信(IPC机制)——管道
- 下一篇: 进程间通信——消息队列