進程通信之信號量

一 信號量(信號燈)概念:

信號量提供一種訪問機制,讓一個臨界區同一時間只有一個進程在訪問他,也就是說信號量用來協調進程對共享資源的訪問的。

信號量是一個特殊的變量,程序對其訪問都是原子操作,只允許對他進行等待(P)和發送信息(V)的操作。最簡單的信號量只能取0和1的變量,這也是信號量最常見的一種形式,叫做二進制信號量。可以取多個正整數的信號量稱爲信號量。

信號量與其他進程間通信方式不大相同,主要用途是保護臨界資源。進程可以根據他判斷是否能夠訪問某些資源。


當進程A要獲取臨界資源S時,首先要獲取臨界資源的信號量M,M的初始值爲1,當獲取到M並發現M的值大於1時,可以反問臨界資源M,且信號量-1,M=0。當進程B也要訪問臨界資源S時,也要首先獲取臨界資源S的信號量M,發現M的值爲0時,無法獲取臨界資源S,進程B阻塞等待。當進程A訪問完臨界資源後,信號量M加1,變爲M=1,同時喚醒進程B,使得B能夠訪問臨界資源S,以此類推,交替訪問臨界資源S。

二 信號量創建:int semget(key_t key, int num_sems, int sem_flags); 成功返回一個相應信號標識符,失敗返回-1

1,key 鍵值,由ftok提供,第一個參數key是整數值(唯一非零),不相關的進程可以通過它訪問一個信號量,它代表程序可能要使用的某個資源,程序對所有信號量的訪問都是間接的,程序先通過調用semget函數並提供一個鍵,再由系統生成一個相應的信號標識符(semget函數的返回值),只有semget函數才直接使用信號量鍵,所有其他的信號量函數使用由semget函數返回的信號量標識符。

2,num_sems指定需要的信號數目,它的值幾乎總是1;

3,sem_flags 是一組標誌,當想要當信號量不存在時創建一個新的信號量,可以和值IPC_CREAT做按位或操作。設置了IPC_CREAT標誌後,即使給出的鍵是一個已有信號量的鍵,也不會產生錯誤。而IPC_CREAT | IPC_EXCL則可以創建一個新的,唯一的信號量,如果信號量已存在,返回一個錯誤。

三 操作 :改變信號量的值

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

1,sem_id 是由semget返回的信號量標識符

2,sembuf

 struct sembuf

{
    short sem_num;//除非使用一組信號量,否則它爲0
   short sem_op;//信號量在一次操作中需要改變的數據,通常是兩個數,一個是-1,即P(等待)操作,
                    //一個是+1,即V(發送信號)操作。
        short sem_flg;//通常爲SEM_UNDO,使操作系統跟蹤信號,
                    //並在進程沒有釋放該信號量而終止時,操作系統釋放信號量
};
3, nsops:信號操作結構的數量,恆大於或等於1

四 控制 int semctl(int sem_id, int sem_num, int command, ...); 

如果有第四個參數,它通常是一個union semum結構,定義如下:
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *arry;
}; 

1,sem_id信號量標識符

2,操作信號在信號集中的編號,第一個信號的編號是0

3,command:

STEVAL:把信號量初始化爲一個已知的值。P這個值通過union semun中的val成員設置,其作用是在信號量第一次使用前對他進行設置

IPC_RMID:刪除一個無需使用的信號量標識符

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun 
{
   int              val;    /* Value for SETVAL */
   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
   unsigned short  *array;  /* Array for GETALL, SETALL */
   struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux specific) */
};

int sem_init(int sem_id)
{
	//int semctl(int semid, int semnum, int cmd, ...);
	union semun sem;
	sem.val = 1;
	int ret = semctl (sem_id,0,SETVAL,sem);//信號量的初始化
	if(ret == -1)
	{
		perror("semctl ");
		return -1;
	}
	return 0;
}

int sem_del(int sem_id)
{
	int ret = semctl (sem_id,0,IPC_RMID);//刪除信號量
	if(ret == -1)
	{
		perror("semctl ");
		return -1;
	}
	return ret;
}

//信號量的P操作
int sem_p(int sem_id)
{
	struct sembuf sem;
	sem.sem_num = 0;
	sem.sem_op = -1;
	sem.sem_flg = SEM_UNDO;
	
	int ret = semop(sem_id,&sem,1);
	return ret;
}

//信號量的V操作
int sem_v(int sem_id)
{
	struct sembuf sem;
	sem.sem_num = 0;
	sem.sem_op = 1;
	sem.sem_flg = SEM_UNDO;
	
	int ret = semop(sem_id,&sem,1);
	return ret;
}


發佈了58 篇原創文章 · 獲贊 12 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章