函数原型
/* 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 函数介绍
int semget (key_t __key, int __nsems, int __semflg);
如果key不存在,且带有cteate标志则创建,如果已经存在则直接返回id
- key:ipc的键,用于与semid匹配
- nsems:信号聚焦信号的数量
- flag:创建的控制选项
semctl 函数介绍
int semctl (int __semid, int __semnum, int __cmd, …);
- semid 通过semget 返回的id
- semnum 要操作第几个信号量
- cmd 命令,支持的命名如下
| 命令 | 说明 |
|---|---|
| IPC_STAT | 从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中 |
| IPC_SET | 设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值 |
| IPC_RMID | 从内核中删除信号量集合 |
| GETALL | 从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中 |
| GETNCNT | 返回当前等待资源的进程个数 |
| GETPID | 返回最后一个执行系统调用semop()进程的PID |
| GETVAL | 返回信号量集合内单个信号量的值 |
| GETZCNT | 返回当前等待100%资源利用的进程个数 |
| SETALL | 与GETALL正好相反 |
| SETVAL | 用联合体中val成员的值设置信号量集合中单个信号量的值 |
semop 函数介绍
int semop (int __semid, struct sembuf *__sops, size_t __nsops)
对信号量聚焦的信号量进行加减操作
- semid: semphore 句柄
- ops 操作选项
struct sembuf {
unsigned short sem_num; /* 需要操作的信号量编号 */
short sem_op; /* 对信号量值进行加减的值 */
short sem_flg; /* 操作选项 */
}
如果sem_op 为正值,表明对信号量进行v操作,会将信号量的值加上sem_op的值
如果sem_op 为负值,表明对信号量进行p操作,会将信号量的值减上sem_op绝对值,
如果减上之后小于0,如果指定了IPC_NOWAIT,则semop返回出错返回EAGAIN,如果没有指定则会阻塞
/* 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位是用户、用户组、其他用户的读写执行权限,如 0777
创建的时候要带上IPC_CREAT 和IPC_EXCL标志
/**
* @file sem_lsw.c
* @author lisiwen (lisiwen945@163.com)
* @brief 实现两个进程的同步读写
* @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;
// 创建信号量集,初始化semums个信号灯 和信号灯的值
int SemCreate(int value, int semnums) {
// 创建信号箱集
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;
// 初始化信号量聚焦所有信号量灯的值
if (semctl(semid, 0, SETALL, un) < 0) {
perror("semctl error");
return -1;
}
free(array);
printf("create semaphore %d success
", semid);
return semid;
}
// 对信号量聚焦的具体的信号灯作PV操作, semnum 是要操作的第几个信号
// p 操作对信号的value -1
// v 操作对信号的value +1
void SemP(int semnum) {
int semid = semget(key, 2, 0777);
if (semid < 0) {
perror("semget error
");
return;
}
// 定义sembuf类型的结构体数组,放置若干个结构体变量
// SEM_UNDO表明进程退出如果没有释放,则代为释放
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
");
return;
}
struct sembuf ops[] = {{semnum, 1, SEM_UNDO}};
if (semop(semid, ops, sizeof(ops) / sizeof(struct sembuf)) < 0) {
perror("semop error");
}
}
// 销毁信号量集
void SemDel() {
int semid = semget(key, 2, 0777);
if (semid < 0) {
perror("semget error
");
return;
}
// 0 表明对所有信号量进行操作
if (semctl(semid, 0, IPC_RMID, NULL) < 0) {
perror("semop error");
}
printf("del semaphore %d success
", 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
", 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
", i);
SemV(SEM_RECV);
}
} else if (strcmp(argv[1], "create") == 0) {
int value = 0; // 初始value为0
int semnums = 2; // 构建两个信号量
SemCreate(value, semnums);
} else if (strcmp(argv[1], "del") == 0) {
SemDel();
}
}
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...


