linux进程间通信:system V 信号量
生活随笔
收集整理的這篇文章主要介紹了
linux进程间通信:system V 信号量
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 概念描述
- 通信原理
- 編程接口
- 使用流程
- 編程案例
概念描述
- 英文:
semaphore簡稱SEM,主要用來進行進程間同步 - 本質:內核維護的一個正整數,可對其進行各種+/-操作
- 分類:systemV 信號量、POSIX 有名信號量、POSIX 無名信號量
- 用途:用來標示系統中可用資源的的個數,協調各個進程有序的訪問資源,防止發生沖突
- P操作:程序在進入臨界區之前要對資源進行申請
- V操作:程序離開臨界區后要釋放相應的資源
通信原理
- 類似于房卡,不是單個值,而是一組(實際上是數組)信號量元素構成
- 將信號量初始設置成一個絕對值
- 在信號量當前值的基礎上加一個數量
- 在信號量當前值的基礎上減去一個數量,降到0以下再去訪問會引起阻塞
- 阻塞進程一直等待其他進程修改該信號量的值,直到恢復正常運行
- 信號量本身無意義,通常會與一塊臨界資源(共享內存)關聯使用
編程接口
-
獲取信號量ID
a. 頭文件<sys/ipc.h> <sys/sem.h>
b.int semget(key_t key,int nsem, int semflg)
c. 函數參數:key:用來表示信號量的鍵,通常使用值IPC_PRIVATE或者由ftok創建nsem: 信號的數量,所有的信號量放在一個數組里semflg:位掩碼,用來設置信號量的權限或者檢查一個已有信號量的權限
IPC_CREAT: 如果找不到指定的key相關聯的信號量,創建一個信號量集合
IPC_EXCL: 若指定了IPC_CREAT且指定key相關聯的信號量存在,報EXIST錯誤
d. 返回值
- 成功:返回操作信號量描述符
- 失敗:返回-1
-
設置信號量
a. 頭文件<sys/ipc.h> <sys/sem.h>
b.int semctl(int semid, int semnum, int cmd ..)
c. 函數參數:semid: 信號量的描述符,標識符;用于操作信號量semnum: 信號量的數量,所有的信號量放在一個數組內cmd:
IPC_RMID :刪除信號量及相關聯的內核smid_ds數據結構
IPC_STAT: 獲取semid_ds的副本
IPC_SET: 設置semid_ds的數據結構
GETVAL: 獲取信號集中地 semnum個信號量的值
GETALL: 獲取所有信號量的值
SETVAL: 設置信號集中的第semnum個信號量的值
d. 函數返回值
- 成功:根據cmd命令,返回不同的值
- 失敗:-1
-
信號量P/V操作
a. 頭文件<sys/ipc.h> <sys/sem.h>
b.int semop(int semid,struct sembuf *sops, size_t nsops);
c. 函數參數:semid:信號的IPC標識符sops: 指向數組的指針,數組中包含了需要執行的操作struct sembuf {unsigned short sem_num; // 標識要操作的信號集中的信號量/*sem_op如下信息:a.若大于0 將sem_op的值加到信號量值上b. 若等于0 ,則對信號量進行檢查,確定其當前值是否為0,若為0則操作結束;若不為0,則一直阻塞,直到為0結束c. 若小于0,則將信號量值減去sem_op,最后結果大于或等于0,操作立即結束;若最后結果小于0,則當前進程會阻塞*/short sem_op;/*信號操作對標記,SEM_UNDO,IPC_NOWAIT*/short sem_flag; }nsops:數組的大小
d. 返回值
- 成功:根據cmd命令,返回不同的值
- 失敗:-1,并設置errno全局變量
使用流程
- 使用semget 創建或打開一個信號量集
- 使用semctl SETVAL 或 SETALL 操作初始化集合中的信號量(其中一個進程操作即可,內核中維護,對其它進程是全局可見的)
- 使用semop操作信號量的值,多個進程通過多信號量值的操作來表示一些臨界資源的獲取和釋放
- 當所有進程不再需要信號量集時,使用semctl IPC_RMID 操作刪除這個信號量集(其中一個進程操作即可)
編程案例
sem_create.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>union semnum {int val;struct semid_ds *buf;unsigned short int *array;struct seminfo *__buf;
};int main ()
{int sem_id;key_t key;if ((key =ftok(".",111)) == -1) {printf("create key failed \n");_exit(-1);}//使用semget 創建或打開一個信號量集if ((sem_id = semget(key,3,IPC_CREAT | 0770)) == -1) {printf("create shm_id failed \n");_exit(-1);} printf("sem_id is :%d\n",sem_id);//獲取信號量中的值int sem_value;sem_value = semctl(sem_id , 0, GETVAL);printf("sem value is %d\n",sem_value);//使用semctl SETVAL 或 SETALL 操作初始化集合中的信號量。通過sem_union設置信號量的值union semnum sem_union;sem_union.val = 2;semctl(sem_id, 0, SETVAL, sem_union);sem_value = semctl(sem_id ,0, GETVAL);printf("sem value after reset is %d\n",sem_value);//使用semop操作信號量,對信號量進行pv操作,這里是-1struct sembuf sops,sops2,sops3;sops.sem_num = 0;sops.sem_op = -1;sops.sem_flg = SEM_UNDO;/*sops.sem_num = 1;sops.sem_op = -1;sops.sem_flg = SEM_UNDO;sops.sem_num = 2;sops.sem_op = -1;sops.sem_flg = SEM_UNDO;*/if( -1 == (semop(sem_id,&sops, 1)) ) {printf("semop set failed \n");_exit(-1);}sem_value = semctl(sem_id, 0, GETVAL);printf("sem value after semop is %d\n",sem_value);sleep(30);semctl(sem_id, 0 ,IPC_RMID);return 0;
}
最終的輸出如下:
sem_id is :524314
sem value is 0
sem value after reset is 2
sem value after semop is 1
總結
以上是生活随笔為你收集整理的linux进程间通信:system V 信号量的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux进程间通信:system V
- 下一篇: 谢字个性签名怎么写