進程間通訊之---信號量淺談以及小例子

           衆所周知,進程間通訊有三種方式,信號量、消息隊列和共享內存。不過信號量我的感受不像通訊,其實就是一個鎖的東西。html

                 這部份內容分幾個部分數據結構

                1.API函數

                 建立信號量   int semget(key_t key,int nsems,int semflg);  返回值就是信號量標識semid  spa

key:所建立或打開信號量集的鍵值。
nsems:建立的信號量集中的信號量的個數,該參數只在建立信號量集時有效。
flag:調用函數的操做類型,也可用於設置信號量集的訪問權限,二者經過or表示
    操做信號量   int semctl(int semid,int semnum,int cmd, /*union semun arg*/);  cmd表示操做類型,具體本身查資料吧,內容太大了;
   PV 操做經過調用semop函數來實現:int semop(int semid,struct sembuf *sops,size_t nsops);
             這裏涉及到兩個內核的數據結構,一個是union semun ,另外一個是sembuf
    先說sembuf,是一個結構體,要熟記,結構以下:
struct sembuf{
unsigned short sem_num;
short sem_op;
short sem_flg;
} 在sembuf結構中,sem_num是相對應的 信號量集 中的某一個資源,因此其值是一個從0到相應的信號量集的資源總數(ipc_perm.sem_nsems)之間的整數。sem_op指明所要執行的操做,sem_flg說明 函數 semop的行爲。sem_op的值是一個整數,如表2所示,列出了詳細sem_op的值及所對應的操做。
sem_op值詳解(關鍵)
Sem_op
操 做
正數
釋放相應的資源數,將sem_op的值加到信號量的值上
0
進程阻塞直到信號量的相應值爲0,當信號量已經爲0,函數當即返回。若是信號量的值不爲0,則依據sem_flg的IPC_NOWAIT位決定函數動做。sem_flg指定IPC_NOWAIT,則semop函數出錯返回EAGAIN。sem_flg沒有指定IPC_NOWAIT,則將該信號量的semncnt值加1,而後進程掛起直到下述狀況發生。信號量值爲0,將信號量的semzcnt的值減1,函數semop成功返回;此信號量被刪除(只有超級用戶或建立用戶進程擁有此權限),函數smeop出錯返回EIDRM;進程捕捉到信號,並從信號處理函數返回,在此狀況將此信號量的semncnt值減1,函數semop出錯返回EINTR
負數
請求sem_op的絕對值的資源。若是相應的資源數能夠知足請求,則將該信號量的值減去sem_op的絕對值,函數成功返回。當相應的資源數不能知足請求時,這個操做與sem_flg有關。sem_flg指定IPC_NOWAIT,則semop函數出錯返回EAGAIN。sem_flg沒有指定IPC_NOWAIT,則將該信號量的semncnt值加1,而後進程掛起直到下述狀況發生:當相應的資源數能夠知足請求,該信號的值減去sem_op的絕對值。成功返回;此信號量被刪除(只有超級用戶或建立用戶進程擁有此權限),函數smeop出錯返回EIDRM:進程捕捉到信號,並從信號處理函數返回,在此狀況將此信號量的semncnt值減1,函數semop出錯返回EINTR
而後再說semun:
union semun
{
     int val;
     struct semid_ds *buf;
     unsigned short int *array;
     struct seminfo *__buf;
};      這裏面要用到的變量是val

2 直接上小例子吧,這樣容易理解:producer.c 創建一個信號量 每隔3秒對val值不停減1;customer.c 讀取val值,直到val=0
producer.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
union semun//因爲類型是union 須要在這裏初始化一下
{
     int val;
     struct semid_ds *buf;
     unsigned short int *array;
     struct seminfo *__buf;
};
int main(int argc, char const *argv[])
{
	int semid;
	key_t key;
	key=ftok(".",3);  //ftok的做用就是計算一個key值供使用,通常用當前目錄文件結點索引號來計算,如指定文件的索引節點號爲65538,換算成16進製爲0x10002,而你指定的ID值爲38,換算成16進製爲0x26,則最後的key_t返回值爲0x2610002。
	semid=semget(key,1,IPC_CREAT|0666);//建立並獲得信號量id
	if(semid==-1){
		perror("semget");
		exit(1);
	}
	printf("my semid is %d \n",semid);
	struct sembuf sbuf={0,-1,IPC_NOWAIT};// 上面sembuf結構體介紹中說,當sem_op=負數,請求sem_op的絕對值的資源。若是相應的資源數能夠知足請求,則將該信號量的值減去sem_op的絕對值,函數成功返回。當相應的資源數不能知足請求時,這個操做與sem_flg有關。sem_flg指定IPC_NOWAIT,則semop函數出錯返回EAGAIN。
	union semun semopts; 
	semopts.val=5;  //對val賦值
	if((semctl(semid,0,SETVAL,semopts))==-1){  // SETVAL就是給semun.val賦值的動做
		perror("semctl");
		exit(1);
	}
	printf("%s\n","ke" );
	while(1){
		if(semop(semid,&sbuf,1)==-1)  // 這個操做就是semop來對{0,-1,IPC_NOWAIT}對應的動做  不斷-1,直到=0
			exit(1);
		sleep(3);
	}
	return 0;
}
customer.c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
int main(int argc, char const *argv[])
{
	int semid,semval;
	key_t key;
	key=ftok(".",3);  //必須仍然用這兩個值計算,否則信號量對應不起來,固然前提是兩個代碼位於相同的路徑下
	semid=semget(key,1,IPC_CREAT|0666); 
	if(semid==-1){
		perror("semget");
		exit(1);
	}
	int val;
	while(1){
		if((semval=semctl(semid,0,GETVAL,0))==-1)//GETVAL獲得semun.val值
			exit(1);
		if(semval>0)
			printf("val is %d\n",semval);
		else{
			printf("stop!\n");
			break;
		}
		sleep(3);
	}
	return 0;
}
結果:
val is 4
val is 3
val is 2
val is 1
stop!
 兩個進程確實通訊成功。
相關文章
相關標籤/搜索