消息隊列、信號量、共享內存各個函數

信號量

信號量是一個特殊的整數值,主要用來控制多個進程對臨界資源的互斥訪問,進程根據信號量來判斷是否有 訪問的資源,這與前面所講的信號是不同的,信號是一種處理異步事件的方法,而信號量是一種進程同步機制,信號與信號量是兩個不同的東西。

信號量是一個計數器,可用於同步多進程對共享數據對象得訪問,爲了獲得共享資源,進程需要執行以下操作:

1、測試控制該資源的信號量

2、若此信號量的值爲正,則進程可以使用該資源,進程將信號量值減1,表示它使用了一個資源單位

3、若此信號量的值爲0,則進程進入睡眠狀態,直至信號量值大於0。當進程被喚醒後,它返回至第1步。

當進程不再使用由一個信號量控制得共享資源時,該信號量值增1.如果有進程正在睡眠以等待此信號量,則喚醒他們,爲了正確地實現信號量,信號量值得測試及減1操作應當是原子操作,爲此,信號量通常是在內核中實現得。

常用的信號量一般初始值爲1,只控制單個資源,有時也稱互斥鎖,但是,信號量得初值可以是任意一正值,該值說明有多少個共享資源單位可供共享應用,信號量有以下3個特性:

1、信號量並非是一個非負值,而必須將信號量定義爲含有一個或多個信號量值得集合,當創建一個信號量時,要指定該集合中的各個值。(linux/sem.h   struct semid_ds)

struct sem

{

ushort_t   semvl;

short        sempid;

ushort      semncnt;

ushort      semzcnt;    

};

2、創建信號量對其賦初值分開,這是一個致命弱點,因爲不能原子地創建一個信號量集合,並且對該集合中的所有值賦初值。

3、即使沒有進程使用,但他們仍然存在,因此必須考慮在進程終止時有沒有釋放得信號量。

以上的三個特性就導致了信號使用的複雜性。

信號量的值通過PV原語來進行操作改變的。

     

Linux中,系統提供了信號量的操作函數,主要有以下函數:

◆key_t  ftok(char *pathname,  char proj);

  根據參數pathnameproj 來創建一個關鍵字,成功時返回與路徑pathname相對應的一個鍵值,具有唯一性,失敗時返回值爲-1.

◆int  semget (key_t  key,  int  nsems ,  int  semflg);

  創建一個新信號量或者取得一個現有的信號量,key是一個關鍵字,可以是用ftok()函數創建的,也可以是IPC_PRIVATE/usr/include/bits$ vi ipc.h

),nsems表明創建的信號量個數,semflg是設置信號量的訪問權限標誌,函數調用成功時返回信號量ID,失敗則返回-1.

◆int semop (int semid, struct sembuf *spos, int nspos);

  對信號量進行操作的函數,用於改變信號量的鍵值,semid是信號量的標誌,spos是指向一個結構體數組的指針,表明要進行什麼操作,nspos表明數組的元素個數,調用成功則返回0,失敗則返回-1.

/usr/include/linux$ vi sem.h  (sembuf \ semun)

 Struct sembuf  (/usr/include/sys$ vi sem.h)

 {

Unsigned short sem_num; /*sem index in array*/

Short sem_op; /* sem operation */

Short sem_flg;/* operation flags */ sem_flg&IPC_RND 0

};

其中,如果sem_op大於0,那麼操作值加入到信號量的值中,並喚醒等待信號增加的進程,如果sem_op爲0,當信號量的值是0的時候,函數返回,否則阻塞直到信號量的值爲0,如果sem_op小於0,函數判斷信號量的值加上這個負值,如果結果爲0喚醒等待信號量爲0的進程,如果小於0函數阻塞,如果大於0,那麼從信號量裏面減去這個值並返回。

◆int semctl (int semid, int semnum, int cmd,  union semun arg);

該函數得作用是對信號量進行一系列得控制,semid是要操作得信號量標誌,semnum是信號量得下標,cmd是操作的命令,經常用的兩個命令是:SETVALIPC_RMIDarg用於設置或返回信號量信息。

 Union semun

{

int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *__buf;

void *__pad;

}


消息隊列

消息隊列是將消息按隊列的方式組織成的鏈表,每個消息都是其中的一個節點。

消息隊列的運行方式與命名管道非常相似。欲與其他進程通信的進程只要將消息發送到消息隊列中,目的進程就從消息隊列中讀取需要的消息。需要注意的是,消息隊列的長度以及每個消息的大小都是有限制的。

Linux系統提供的消息隊列操作函數主要有以下幾個:

int msgget(key_t key,int msgflg);

int msgsnd(int msqid, const void *msgptr,  int msgsz,int msgflg);

int msgrcv(int msqid, void *msgptr, int msgsz, long msgtyp, int msgflg);

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msgget()函數與信號量的semget()函數相似,作用是創建一個消息隊列。參數key是一個鍵值,可由用戶設定也可通過ftok()函數獲得。Msgflg參數設置的是一些標誌位,可以是IPC_CREATIPC_EXCLIPC_NOWAIT中的一個或者他們的組合。創建成功則返回消息隊列ID;否則返回-1

Msgsnd()函數的作用是將消息發送到消息隊列中去。Msqid爲消息隊列IDMsgptr是指想要發送的消息的指針,並且指向的緩衝區的第一個字段應爲長整形,指定消息類型,消息內容存放在該緩衝區的緊跟消息類型字段的區域中。Msgsz是要發送的消息的長度。Msgflgmsgget()函數中的msgflg參數設置類似,設置當消息隊列滿等情況出現時的處理方式,如果msgflg設置爲IPC_NOWAIT,則不發送消息並且立即返回-1;否則發送進程掛起等待。

如果msgsnd()函數調用成功,就會把消息複製到消息隊列中去並返回0;否則返回-1

Msgrcv()函數的作用是從消息隊列中讀取一個消息。Msqid是消息隊列的IDMsgptr保存從消息隊列中讀到的消息。Msgszmsgptr指向的消息的長度。Msgtyp指定要求的消息類型,見表

Msgrcv()函數msgtyp參數說明

Msgtyp取值

說明

大於0

接收消息隊列中類型爲msgtyp的第一個可用報文

等於0

接收消息隊列中的第一個可用報文

小於0

接收消息隊列中小於或等於msgtyp絕對值的第一個可用報文

Msgflg的設置與msgsnd()函數中 的參數msgflg設置類似,用於設置如何處理當前消息隊列中沒有滿足條件的消息的情況。

如果msgrcv()函數調用成功,則返回讀出的實際字節數;否則返回-1.

Msgctl()函數是消息隊列的控制函數,類似於信號量的控制函數semctl()Msqid是消息隊列的IDCmd是要採取的控制操作,有3個可取值,見表

參數值

說明

IPC_SET

設置消息隊列的屬性,將buf指向的結構體中的數值設置爲消息隊列的相關性

IPC_STAT

獲取消息隊列的屬性信息並保存到buf指向的結構體中

IPC_RMID

移除IDmsqid的消息隊列

 

 

共享內存

共享內存是系統創建的特殊地址空間,允許不相關的多個進程使用這個內存空間,即多個進程能夠使用同一塊內存中的數據。

共享內存與其他進程通信方式相比較,不需要複製數據,直接讀寫內存,是一種效率非常高的進程通信方案。但它本身不提供同步訪問機制,需要我們自己控制。在LINUX中,只要把共享內存段連接到進程的地址空間中,這個進程就可以訪問共享內存中的地址了。

LINUX系統提供的共享內存操作函數與信號量、消息隊列等類似,主要有以下幾個:

(1) int shmget(key_t key,int shmsz,int shmflg);

(2) void *shmat(int shmid,const void *shmaddr, int shmflg);

如果shmaddr0 則此段連接到由內核選擇的第一個可用地址上,這是推薦的使用方式
如果shmaddr非零,並且沒有指定SHM_RND,則此段鏈接到addr所指的地址上
如果shmaddr非零且指定SHM_RND,則此段鏈接到shmaddr - (addr mod ulus SHMLBA)所表示的地址上。SHM_RND的意思是低邊界地址倍數,它總是2的乘方。該算式是將地址向下取最近的一個SHMLBA的倍數

(3) int shmdt (const void *shmaddr);

(4) int shmctl(int shmid, int cmd,struct shmid_ds *buf);

以上各函數含義如下:

l Shmget()函數分配一塊新的共享內存。Shmsz指明共享內存的大小,以字節爲單位,shmflg的設置與信號量的semget()函數中的參數semflg類似。

如果shmget()函數調用成功則返回共享內存的ID;否則返回-1.

l Shmat()函數的作用是連接共享內存與某個進程的地址空間。Shmidshmget()函數返回的共享內存IDShmaddr是共享內存連接到進程中的存放地址,一般設置爲空指針,表示交由系統完成這個工作。Shmflg設置共享內存的控制選項,有兩個可能取值:SHM_RND(shmaddr參數相關)SHM_RDONLY(只允許讀)。如果shmat()函數調用成功則返回指向共享內存的指針;否則返回-1.

l Shmdt()函數用來解除進程與共享內存區域的關聯,使當前進程不能繼續訪問共享內存。參數shmaddrshmat()函數返回的指針。如果操作成功則返回0;失敗則返回-1.

l Shmctl()函數實現對共享內存區域的控制操作。其用法與消息隊列的msgctl()函數類似。

 

sem. msg. shm 都是創建在/dev/shm目錄下

ipcs

ipcs -s ipcs -q ipcs -m

ipcrm

 

ipcs -s -i sem_id

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章