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进程间通信:system V 信号量和共享内存实现进程间同步
关于信号量和共享内存的相关描述已经在前几篇提到过: 信号量:即内核维护的一个正整数,可以使用内核提供的p/v接口进行该正整数的+/-操作,它主要用来表示系统中可用资源的个数,协调各个进程有序访问资源, ...
- linux进程间通信:system V 信号量
文章目录 概念描述 通信原理 编程接口 使用流程 编程案例 概念描述 英文:semaphore 简称SEM,主要用来进行进程间同步 本质:内核维护的一个正整数,可对其进行各种+/-操作 分类:syst ...
- Linux进程间通信一 System V 共享内存简介与示例
目录 1. System V共享内存简介 2. API介绍 2.0 key_t和标识符 2.1 创建system v共享内存 2.2 映射共享内存并使用 2.3 取消共享内存映射 2.4 控制共享内 ...
- linux进程间通信:system V消息队列
文章目录 基本介绍 编程接口 代码实例 消息队列的发送和接收 消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用 ...
- Linux进程间通信二 System V 消息队列简介与示例
1. SystemV消息队列简介 消息队列,顾名思义即是存放消息的队列,内核为每个SystemV 维护了一个msg_queue的结构体,里面记录了每个消息队列的信息. struct msg_queue ...
- linux进程间通信:system V 共享内存
文章目录 思维导图如下 通信原理 优势 运行流程 编程接口 编程实例 思维导图如下 通信原理 多个进程共享物理内存的同一块区域(通常称之为"段":segment) 抛弃了内核态消息 ...
- Linux进程间通信六 Posix 共享内存简介与示例
1. 共享内存简介 共享内存主要用于不同进程之间相互通信,因为操作的是同一块地址,不需要内核和用户层之间数据拷贝,属于最快的进程间通信方式,不过,为了防止读写冲突,一般需要额外的同步手段.之前介绍了S ...
- Linux进程间通信四 Posix 消息队列简介与示例
目录 1. Posix 消息队列简介 2. API接口 2.1 创建或打开消息队列 2.2 发送消息 2.3 接收消息 2.4 获取.设置消息队列属性 2.5 关闭消息队列 2.6 删除消息队列 2. ...
最新文章
- 干货 | 手把手教你用115行代码做个数独解析器!(附代码)
- mysql mediumtext longtext
- linux查看vnc服务关闭,linux配置vncserver服务
- C++之显示构造函数
- cache目录没有权限
- Linux网络模拟,模拟网络访问解析
- Java中JSON字符串与java对象的互换实例详解
- rsa 模数 指数转换 c语言_模数转换,你必须知道的8个经典ADC转换电路方案
- 终于有人把Python讲清楚了!!
- 【OpenCV】OpenCV函数精讲之 -- 教你如何使用离散傅里叶变换
- HeadFirst设计模式之命令模式
- ubuntu16.xxx安装mysql5.0项目迁移环境搭建
- labview rtm_下载Vista RTM
- CSS+DIV实现圆角
- SOUI中几个view视图控件的基本使用
- 微信第三方授权获取用户信息
- 基于单片机自行车自动防盗报警系统设计-基于单片机温度监测监控报警系统设计-基于单片机智能无线病床呼叫系统设计-基于单片机四路红外遥控开关电路设计【设计资料转发分享】
- 计算机大赛鼓励语录,鼓励参加比赛的话
- Node.js Kubernetes Graceful Shutdown
- 除了同性交友平台 GitHub,程序员们业余时间还可以去哪儿?
热门文章
- 如何构建高扩展性网站?
- python制作猜拳游戏代码_python实现猜拳游戏项目
- 连接php的作用是什么意思,链接是什么?
- P11 非线性系统-《Matlab/Simulink与控制系统仿真》程序指令总结
- 2.2 逻辑回归-机器学习笔记-斯坦福吴恩达教授
- Beyond Compare 3 许可证密钥被撤销
- DC workshop指导篇1- Setup and Synthesis Flow
- 类和对象—对象特性—构造函数和析构函数
- 【arduino】亲测MAC上arduino安装ESP32 SPIFFS插件
- 【arduino】arudino开发ESP32 SPIFFS文件上传方法