Linux进程间通信三 System V 信号量简介与示例
生活随笔
收集整理的這篇文章主要介紹了
Linux进程间通信三 System V 信号量简介与示例
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. System V信號量簡介
SystemV信號量主要用于解決生產者和消費者問題,一個信號量能夠控制多個資源,說它是信號量集也不為過。
2. API接口介紹
2.1 創建或打開信號量集
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>/** * @brief 創建信號量或者返回已存在的信號量 * * @params key 與信號量關聯的key,三種生成方式,包括IPC_PRIVATE,注意key和信號量不是綁定關系,相同的key產生的標識符不一定相同,比如系統重啟的情況 * @params nsems 集合中信號量的個數 * @params shmflg 標志位和權限控制標志位,可以多個用or運算。IPC_CREAT、 IPC_EXCL * * @returns 成功返回信號量集標識符,失敗返回-1 */int semget(key_t key, int nsems, int semflg);2.2 操作信號量集
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>/** * @brief 操作信號量集 * * @params semid 信號量集標識符 * @params sops 具體的操作行為,指向一個數組,每個元素都是sembuf結構,該結構指定了要操作哪個信號量以及相應的值等。 * * @params nsops 表名sembuf的數量 * * @returns 成功返回0,失敗返回-1,注意這里的操作是原子性的,如果操作多個信號量,要么全部成功,要么什么都不做 */int semop(int semid, struct sembuf *sops, size_t nsops);struct sembuf {unsigned short int sem_num; // 指定操作信號量的下標,從0開始short sem_op; // 信號量的值short sem_flg; // 操作標志位,可選 IPC_NOWAIT and SEM_UNDO,前者表示非阻塞,后者標志當進程退出后,系統自動恢復對這個信號量的操作。 };2.3 控制操作
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>/** * @brief 操作信號量集 * * @params semid 信號量集標識符 * @params semnum 要操作的信號量序號,下標從0開始 * @params cmd 控制行為,可選值IPC_STAT,IPC_RMID, IPC_SET, IPC_INFO * @params 可選參數,這里的參數結構體需要用戶自定義。 * @returns 不同的cmd返回不通值 */int semctl(int semid, int semnum, int cmd, ...);// 可選參數,需要用戶自定義 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) */ };3. 示例
下面是信號量集的一個簡單示例,分為生產者和消費者,其中生產者生產資源,消費者消費資源
生產者:
/* ** Name: sem_wait.c ** Desc: 生產者 ** Author: masonf ** Date: 20200626 */#include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>// 自定義結構體 union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf; };int main() {int ret = 0;key_t key = 10240;int sem_id;// 創建或獲取信號量集,其中包含一個信號量,這里key是固定的sem_id = semget(key, 1, IPC_CREAT);if (sem_id == -1){perror("create sem error");return -1;}// 設置第0個信號量,資源數加1struct sembuf sem_operation[1]={0};sem_operation[0].sem_op=1;sem_operation[0].sem_num = 0;// 初始化信號量的值為1if (semop(sem_id, sem_operation, 1) == -1){perror("init sem error");// 初始化失敗則刪除信號量集semctl(sem_id, 1, IPC_RMID);return -1;}int food_nums = 1;while (food_nums < 5){printf("start producing foods\n");// 生產食物sem_operation[0].sem_num=0; // 操作第一個信號量,下標從0開始sem_operation[0].sem_op = 1;while (semop(sem_id, sem_operation, 1) == -1){printf("producing error, continue\n");continue;}++food_nums;}// 刪除信號量集//semctl(sem_id, 1, IPC_RMID);printf("work done, Go home!\n");return 0; }消費者
/* ** Name: sen_wait.c ** Desc: 消費者 ** Author: mason ** Date: 20200626 */#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>// 自定義結構體 union semun {int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf; };int main() {int ret = 0;key_t key = 10240;int sem_id;// 創建或獲取信號量集sem_id = semget(key, 1, IPC_CREAT);if (sem_id == -1){perror("create sem error");return -1;}//操作信號量,默認是阻塞struct sembuf sem_operation[1]={0};sem_operation[0].sem_num=0;sem_operation[0].sem_op=-1; // 申請一個資源//sem_operation[0].sem_flg=SEM_UNDO;// 消費,每次消費一個while (semop(sem_id, sem_operation, 1) != -1){printf("consuming foods\n");}return 0; }?編譯運行
4. 注意事項
4.1?信號量的創建和初始化操作是分開的,這點需要注意,好在有一種解決方法,信號量集相關的結構體中有一個sem_otime字段,初始化為0,可以通過檢查sem_otime是否為0來判斷是否已經經過初始化
?
2. 資源限制
SEMMSL 系統范圍內信號量集的最大數量,可通過/proc/sys/kernel/sem查看 SEMMSL 單個信號量集中信號量的最大個數 SEMMNS 系統范圍內信號量的最大數量?
5.參考文檔
1.?https://man7.org/linux/man-pages/man2/semop.2.html
2. 《Linux環境編程 從應用到內核》
3. 《Unix網絡編程 卷二 進程間通信》
================================================================================================
Linux應用程序、內核、驅動、后臺開發交流討論群(745510310),感興趣的同學可以加群討論、交流、資料查找等,前進的道路上,你不是一個人奧^_^。...
?
總結
以上是生活随笔為你收集整理的Linux进程间通信三 System V 信号量简介与示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux进程间通信二 System V
- 下一篇: Linux进程间通信四 Posix 消息