函數(shù)原型
/* Semaphore control operation. */
extern int semctl (int __semid, int __semnum, int __cmd, ...) __THROW;
/* Get semaphore. */
extern int semget (key_t __key, int __nsems, int __semflg) __THROW;
/* Operate on semaphore. */
extern int semop (int __semid, struct sembuf *__sops, size_t __nsops) __THROW;
semget 函數(shù)介紹
int semget (key_t __key, int __nsems, int __semflg)绍撞;
如果key不存在藕筋,且?guī)в衏teate標(biāo)志則創(chuàng)建,如果已經(jīng)存在則直接返回id
- key:ipc的鍵骚露,用于與semid匹配
- nsems:信號(hào)集中信號(hào)的數(shù)量
- flag:創(chuàng)建的控制選項(xiàng)
semctl 函數(shù)介紹
int semctl (int __semid, int __semnum, int __cmd, ...);
- semid 通過(guò)semget 返回的id
- semnum 要操作第幾個(gè)信號(hào)量
- cmd 命令,支持的命名如下
命令 | 說(shuō)明 |
---|---|
IPC_STAT | 從信號(hào)量集上檢索semid_ds結(jié)構(gòu),并存到semun聯(lián)合體參數(shù)的成員buf的地址中 |
IPC_SET | 設(shè)置一個(gè)信號(hào)量集合的semid_ds結(jié)構(gòu)中ipc_perm域的值默勾,并從semun的buf中取出值 |
IPC_RMID | 從內(nèi)核中刪除信號(hào)量集合 |
GETALL | 從信號(hào)量集合中獲得所有信號(hào)量的值,并把其整數(shù)值存到semun聯(lián)合體成員的一個(gè)指針數(shù)組中 |
GETNCNT | 返回當(dāng)前等待資源的進(jìn)程個(gè)數(shù) |
GETPID | 返回最后一個(gè)執(zhí)行系統(tǒng)調(diào)用semop()進(jìn)程的PID |
GETVAL | 返回信號(hào)量集合內(nèi)單個(gè)信號(hào)量的值 |
GETZCNT | 返回當(dāng)前等待100%資源利用的進(jìn)程個(gè)數(shù) |
SETALL | 與GETALL正好相反 |
SETVAL | 用聯(lián)合體中val成員的值設(shè)置信號(hào)量集合中單個(gè)信號(hào)量的值 |
semop 函數(shù)介紹
int semop (int __semid, struct sembuf *__sops, size_t __nsops)
對(duì)信號(hào)量集中的信號(hào)量進(jìn)行加減操作
- semid: semphore 句柄
- ops 操作選項(xiàng)
struct sembuf {
unsigned short sem_num; /* 需要操作的信號(hào)量編號(hào) */
short sem_op; /* 對(duì)信號(hào)量值進(jìn)行加減的值 */
short sem_flg; /* 操作選項(xiàng) */
}
如果sem_op 為正值聚谁,表示對(duì)信號(hào)量進(jìn)行v操作母剥,會(huì)將信號(hào)量的值加上sem_op的值
如果sem_op 為負(fù)值,表示對(duì)信號(hào)量進(jìn)行p操作垦巴,會(huì)將信號(hào)量的值減上sem_op絕對(duì)值,
如果減上之后小于0媳搪,如果指定了IPC_NOWAIT,則semop返回出錯(cuò)返回EAGAIN骤宣,如果沒(méi)有指定則會(huì)阻塞
/* Mode bits for `msgget', `semget', and `shmget'. */
#define IPC_CREAT 01000 /* Create key if key does not exist. */
#define IPC_EXCL 02000 /* Fail if key exists. */
#define IPC_NOWAIT 04000 /* Return error on wait. */
后面3位是用戶(hù)秦爆、用戶(hù)組、其他用戶(hù)的讀寫(xiě)執(zhí)行權(quán)限憔披,如 0777
創(chuàng)建的時(shí)候要帶上IPC_CREAT 和IPC_EXCL標(biāo)志
/**
* @file sem_lsw.c
* @author lisiwen (lisiwen945@163.com)
* @brief 實(shí)現(xiàn)兩個(gè)進(jìn)程的同步讀寫(xiě)
* @version 0.1
* @date 2021-01-28
*
* @copyright Copyright (c) 2021
*
*/
#include <apue.h>
#include <sys/sem.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
#define SEM_SEND 0
#define SEM_RECV 1
key_t key = 128;
// 創(chuàng)建信號(hào)量集等限,初始化semums個(gè)信號(hào)燈 和信號(hào)燈的值
int SemCreate(int value, int semnums) {
// 創(chuàng)建信號(hào)箱集
int semid = semget(key, semnums, IPC_CREAT | IPC_EXCL | 0777);
if (semid < 0) {
return -1;
}
union semun un;
unsigned short *array = (unsigned short *)calloc(semnums, sizeof(unsigned short));
for (int i = 0; i < semnums; i++) {
array[i] = value;
}
un.array = array;
// 初始化信號(hào)量集中所有信號(hào)量燈的值
if (semctl(semid, 0, SETALL, un) < 0) {
perror("semctl error");
return -1;
}
free(array);
printf("create semaphore %d success\n", semid);
return semid;
}
// 對(duì)信號(hào)量集中的具體的信號(hào)燈作PV操作, semnum 是要操作的第幾個(gè)信號(hào)
// p 操作對(duì)信號(hào)的value -1
// v 操作對(duì)信號(hào)的value +1
void SemP(int semnum) {
int semid = semget(key, 2, 0777);
if (semid < 0) {
perror("semget error\n");
return;
}
// 定義sembuf類(lèi)型的結(jié)構(gòu)體數(shù)組,放置若干個(gè)結(jié)構(gòu)體變量
// SEM_UNDO表示進(jìn)程退出如果沒(méi)有釋放芬膝,則代為釋放
struct sembuf ops[] = {{semnum, -1, SEM_UNDO}};
if (semop(semid, ops, sizeof(ops) / sizeof(struct sembuf)) < 0) {
perror("semop error");
}
}
void SemV(int semnum) {
int semid = semget(key, 2, 0777);
if (semid < 0) {
perror("semget error\n");
return;
}
struct sembuf ops[] = {{semnum, 1, SEM_UNDO}};
if (semop(semid, ops, sizeof(ops) / sizeof(struct sembuf)) < 0) {
perror("semop error");
}
}
// 銷(xiāo)毀信號(hào)量集
void SemDel() {
int semid = semget(key, 2, 0777);
if (semid < 0) {
perror("semget error\n");
return;
}
// 0 表示對(duì)所有信號(hào)量進(jìn)行操作
if (semctl(semid, 0, IPC_RMID, NULL) < 0) {
perror("semop error");
}
printf("del semaphore %d success\n", semid);
}
int main(int argc, char* argv[])
{
if (argc < 2) {
printf("%s arg", argv[0]);
}
if (strcmp(argv[1], "send") == 0) {
for (int i = 0; i < 10; i++) {
sleep(1);
printf("send num %d\n", i);
SemV(SEM_SEND);
SemP(SEM_RECV);
}
} else if (strcmp(argv[1], "recv") == 0) {
for (int i = 0; i < 10; i++) {
SemP(SEM_SEND);
printf("recv num %d\n", i);
SemV(SEM_RECV);
}
} else if (strcmp(argv[1], "create") == 0) {
int value = 0; // 初始value為0
int semnums = 2; // 構(gòu)建兩個(gè)信號(hào)量
SemCreate(value, semnums);
} else if (strcmp(argv[1], "del") == 0) {
SemDel();
}
}