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 信号量简介与示例相关推荐

  1. linux进程间通信:system V 信号量 生产者和消费者模型编程案例

    生产者和消费者模型: 有若干个缓冲区,生产者不断向里填数据,消费者不断从中取数据 两者不冲突的前提: 缓冲区有若干个,且是固定大小,生产者和消费者各有若干个 生产者向缓冲区中填数据前需要判断缓冲区是否 ...

  2. linux进程间通信:system V 信号量和共享内存实现进程间同步

    关于信号量和共享内存的相关描述已经在前几篇提到过: 信号量:即内核维护的一个正整数,可以使用内核提供的p/v接口进行该正整数的+/-操作,它主要用来表示系统中可用资源的个数,协调各个进程有序访问资源, ...

  3. linux进程间通信:system V 信号量

    文章目录 概念描述 通信原理 编程接口 使用流程 编程案例 概念描述 英文:semaphore 简称SEM,主要用来进行进程间同步 本质:内核维护的一个正整数,可对其进行各种+/-操作 分类:syst ...

  4. Linux进程间通信一 System V 共享内存简介与示例

    目录 1. System V共享内存简介 2. API介绍 2.0 key_t和标识符 2.1  创建system v共享内存 2.2 映射共享内存并使用 2.3 取消共享内存映射 2.4 控制共享内 ...

  5. linux进程间通信:system V消息队列

    文章目录 基本介绍 编程接口 代码实例 消息队列的发送和接收 消息队列中的消息对象的属性控制 基本介绍 支持不同进程之间以消息(messages)的形式进行数据交换,消息能够拥有自己的标识,且内核使用 ...

  6. Linux进程间通信二 System V 消息队列简介与示例

    1. SystemV消息队列简介 消息队列,顾名思义即是存放消息的队列,内核为每个SystemV 维护了一个msg_queue的结构体,里面记录了每个消息队列的信息. struct msg_queue ...

  7. linux进程间通信:system V 共享内存

    文章目录 思维导图如下 通信原理 优势 运行流程 编程接口 编程实例 思维导图如下 通信原理 多个进程共享物理内存的同一块区域(通常称之为"段":segment) 抛弃了内核态消息 ...

  8. Linux进程间通信六 Posix 共享内存简介与示例

    1. 共享内存简介 共享内存主要用于不同进程之间相互通信,因为操作的是同一块地址,不需要内核和用户层之间数据拷贝,属于最快的进程间通信方式,不过,为了防止读写冲突,一般需要额外的同步手段.之前介绍了S ...

  9. Linux进程间通信四 Posix 消息队列简介与示例

    目录 1. Posix 消息队列简介 2. API接口 2.1 创建或打开消息队列 2.2 发送消息 2.3 接收消息 2.4 获取.设置消息队列属性 2.5 关闭消息队列 2.6 删除消息队列 2. ...

最新文章

  1. 干货 | 手把手教你用115行代码做个数独解析器!(附代码)
  2. mysql mediumtext longtext
  3. linux查看vnc服务关闭,linux配置vncserver服务
  4. C++之显示构造函数
  5. cache目录没有权限
  6. Linux网络模拟,模拟网络访问解析
  7. Java中JSON字符串与java对象的互换实例详解
  8. rsa 模数 指数转换 c语言_模数转换,你必须知道的8个经典ADC转换电路方案
  9. 终于有人把Python讲清楚了!!
  10. 【OpenCV】OpenCV函数精讲之 -- 教你如何使用离散傅里叶变换
  11. HeadFirst设计模式之命令模式
  12. ubuntu16.xxx安装mysql5.0项目迁移环境搭建
  13. labview rtm_下载Vista RTM
  14. CSS+DIV实现圆角
  15. SOUI中几个view视图控件的基本使用
  16. 微信第三方授权获取用户信息
  17. 基于单片机自行车自动防盗报警系统设计-基于单片机温度监测监控报警系统设计-基于单片机智能无线病床呼叫系统设计-基于单片机四路红外遥控开关电路设计【设计资料转发分享】
  18. 计算机大赛鼓励语录,鼓励参加比赛的话
  19. Node.js Kubernetes Graceful Shutdown
  20. 除了同性交友平台 GitHub,程序员们业余时间还可以去哪儿?

热门文章

  1. 如何构建高扩展性网站?
  2. python制作猜拳游戏代码_python实现猜拳游戏项目
  3. 连接php的作用是什么意思,链接是什么?
  4. P11 非线性系统-《Matlab/Simulink与控制系统仿真》程序指令总结
  5. 2.2 逻辑回归-机器学习笔记-斯坦福吴恩达教授
  6. Beyond Compare 3 许可证密钥被撤销
  7. DC workshop指导篇1- Setup and Synthesis Flow
  8. 类和对象—对象特性—构造函数和析构函数
  9. 【arduino】亲测MAC上arduino安装ESP32 SPIFFS插件
  10. 【arduino】arudino开发ESP32 SPIFFS文件上传方法