Linux 系统下的进程间通信 IPC 入门 「中」

以下内容为本人的学习笔记,如需要转载,请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/39XQUQtGC3Ow-0s0JKWnog

信号量

信号量一般用于配合共享内存的数据传输,共享内存被多个进程之间共享访问,各个进程对共享内存的访问必须被同步才安全和有效。

申请信号量资源时,返回的是一组信号量集合,包含多个信号量,信号量 id 对应的是信号量集合,而不是单个信号量,每个信号量可以分别控制各种同步。信号量通过序号指定,序号从 0 开始。

系统范围内,可以申请的最多信号量集合数为 32000 个,每个信号量集合最多包含的信号量为 32000 个,每个信号量调用的最大操作数是 500,信号量值最大可达 32767。如果需要查看限制值,可以:

$ cat /proc/sys/kernel/sem

通过 semget() 申请信号量集合,参数 key 指定 IPC key,参数 nsems 指定包含的信号量数量。参数 semflg = IPC_CREAT | IPC_EXCL 指定尝试创建信号量,如果已经存在则返回失败,失败后可重新尝试获取。

int semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
if (-1 == semid) {  // failure
    semid = semget(key, nsems, 0666);
    if (-1 == semid) {
        printf("semget %s", strerror(errno));
    }
}

信号量通过请求(抢占)和释放来控制进程间同步,本质上就是满足一定条件下对信号量值的加减。每个信号量有一些关联的变量,比如信号量值 semval。

请求信号量

/**
 * @brief           请求信号量
 * @param id        信号量集合 id
 * @param semindex  信号量序号,从 0 开始
 * @param val       信号量值偏移绝对值,一般为 1
 */
void sem_set_wait(int id, int semindex, short val)
{
    int ret;
    struct sembuf buf;

    buf.sem_num = semindex;
    // P(sv) 减1 获取信号量
    buf.sem_op  = (-1) * val;
    buf.sem_flg = 0;

    while ((ret = semop(id, &buf, 1))
            && (errno == EINTR));
    if (ret == -1) {
        perror("semop");
    }
}

请求信号量,也就是常说的 P 操作,实际是对信号量值做减法操作,如果当前信号量值比减数的绝对值小,那么一般情况下会阻塞当前线程。是否阻塞可以通过设置标志 sembuf.sem_flg 来决定。

释放信号量

/**
 * @brief           释放信号量
 * @param id        信号量集合 id
 * @param semindex  信号量序号,从 0 开始
 * @param val       信号量值偏移绝对值,一般为 1
 */
void sem_set_signal(int id, int semindex, short val)
{
    struct sembuf buf;

    buf.sem_num = semindex;
    // V(sv) 加1 释放信号量
    buf.sem_op  = val;
    buf.sem_flg = 0;

    if (semop(id, &buf, 1) == -1) {
        perror("semop");
    }
}

释放信号量,也就是常说的 V 操作,实际是对信号量值做加法操作,不会阻塞当前线程。

最佳实践

如果有两个数据生产消费端,一个生产端和一个消费端,为了实现先生产再消费,消费完再生产,以及以此类推的同步流程,那么可以从信号量集合中使用其中的两个信号量,比如信号量 0 和信号量 1。

生产端:

// 请求信号量 0
sem_set_wait(semid, 0, 1);

// 生产 ...

// 释放信号量 1
sem_set_signal(semid, 1, 1);

消费端:

// 请求信号量 1
sem_set_wait(semid, 1, 1);

// 消费 ...

// 释放信号量 0
sem_set_signal(semid, 0, 1);

请求信号量 0,那么信号量 0 应该先被释放,信号量 1 同理。生产端生产前需要请求信号量 0,消费端消费前需要请求信号量 1,生产完成后释放信号量 1,消费完成后释放信号量 0。意味着生产前必须先消费,消费前必须先生产。

这样子相互依赖的逻辑决定了必须另一端执行完毕,当前端才可以开始执行。

既然是相互依赖,就必须有切入点,那么实际运行开始时,需要先允许生产端请求到信号量,可以设置信号量 0 的值为 1,这样生产端就可以顺利请求信号量 0 并开始生产,生产完成后再释放信号量 1,接着消费端才能够顺利请求到信号量 1。

设置信号量的值需要用到 semctl():

#include <sys/sem.h>
union semun {
    /* Value for SETVAL */
    int              val;
    /* Buffer for IPC_STAT, IPC_SET */
    struct semid_ds *buf;
    /* Array for GETALL, SETALL */
    unsigned short  *array;
    /* Buffer for IPC_INFO (Linux-specific) */
    struct seminfo  *__buf;
};

int semctl(int semid, int semnum, int cmd, ...);

semctl() 有 4 个参数,semid 指定信号量集合 id,semnum 指定信号量集合中的信号量序号,cmd 指定对信号量的操作命令,最后一个参数可选。

semctl() 可用于信号量的各种设置,当 cmd = SETVAL 时,设置共用体 semun 类型的 val 成员为信号量的目标值,然后值传递 semun 类型变量给 semctl() 最后一个参数,代码如下

/**
 * @brief       初始化信号量值
 * @param id        信号量集合 id
 * @param semindex  信号量序号,从 0 开始
 * @param val       信号量初始值
 * @return int  0:成功,-1:失败
 */
int sem_init(int id, int semindex, int val)
{
    union semun su;

    su.val = val;
    if (semctl(id, semindex, SETVAL, su) == -1) {
        perror("semctl");
        return -1;
    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/556284.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arcade 用户界面textarea

# 导入所需库 import arcade import arcade.gui# 创建窗口类 class MyWindow(arcade.Window):# 初始化方法def __init__(self):super().__init__(800, 600, "GUI Widgets Example", resizableTrue)# 创建UI管理器&#xff0c;用于处理UI元素self.manager arcade.gui…

2024Mathorcup数学应用挑战赛C题|图神经网络的预测模型+ARIMA时间序列预测模型+人员排班混合整数规划模型|完整代码和论文全解全析

2024Mathorcup数学应用挑战赛C题|图神经网络的预测模型ARIMA时间序列预测模型人员排班混合整数规划模型|完整代码和论文全解全析 我们已经完成了2024Mathorcup数学建模挑战赛C题的40页完整论文和代码&#xff0c;相关内容可见文末&#xff0c;部分图片如下&#xff1a; 问题分…

N元语言模型

第1关&#xff1a;预测句子概率 任务描述 本关任务&#xff1a;利用二元语言模型计算句子的概率 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.条件概率计算方式。 2.二元语言模型相关知识。 条件概率计算公式 条件概率是指事件A在事件B发生的条件下发…

Golang | Leetcode Golang题解之第36题有效的数独

题目&#xff1a; 题解&#xff1a; func isValidSudoku(board [][]byte) bool {var rows, columns [9][9]intvar subboxes [3][3][9]intfor i, row : range board {for j, c : range row {if c . {continue}index : c - 1rows[i][index]columns[j][index]subboxes[i/3][j/3]…

【每日一题】2007. 从双倍数组中还原原数组-2024.4.18

题目&#xff1a; 2007. 从双倍数组中还原原数组 一个整数数组 original 可以转变成一个 双倍 数组 changed &#xff0c;转变方式为将 original 中每个元素 值乘以 2 加入数组中&#xff0c;然后将所有元素 随机打乱 。 给你一个数组 changed &#xff0c;如果 change 是 双…

如何获得合适的助听器?

要获得一个合适的助听器&#xff0c;您可以按照以下步骤进行&#xff1a; 1. 咨询专业医生或听力专家&#xff1a;首先&#xff0c;建议您咨询专业的耳鼻喉科医生或听力专家。他们可以通过听力测试来评估您的听力损失程度和类型&#xff0c;并为您提供个性化的建议。 2. 选择信…

DevOps是什么?

DevOps是一系列实践、工具和文化理念的组合&#xff0c;旨在自动化并整合软件开发和信息技术运维团队之间的流程。以下是DevOps的几个关键点&#xff1a; 沟通与协作&#xff1a;DevOps强调开发和运维团队之间的沟通与合作&#xff0c;通过改善这两个部门间的协作关系&#xff…

Labview2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 LabVIEW是一种由美国国家仪器&#xff08;NI&#xff09;公司开发的程序开发环境&#xff0c;它显著区别于其他计算机语言&#xff0c;如C和BASIC。传统的计算机语言是基于文本的语言来产生代码&#xff0c;而LabVIEW则采用图形化…

JavaEE:File类查询一个文件的路径(举例+源码 )

一、File类概述 Java 中通过 java.io.File 类来对一个文件&#xff08;包括目录&#xff09;进行抽象的描述。File 类中的方法可以对文件路径以及文件名等信息进行查询&#xff0c;也可以对文件进行各项增删改操作&#xff0c;本文主要介绍 File 类的查询方法。 二、代码示例 …

计算机系统基础知识总结

一、计算机系统概述 计算系统可以分为硬件和软件两部分。硬件主要有中央处理器、存储器、输入和输出设备组成&#xff1b;软件由系统软件和应用软件组成。 冯诺依曼计算机体系&#xff1a;将硬件划分为&#xff1a;输入、输出、运算器、存储器、控制器五部分。 中央处理器&…

【WP】猿人学4 雪碧图、样式干扰

https://match.yuanrenxue.cn/match/4 探索 首先打开Fiddler&#xff0c;发现每个包的除了page参数一样&#xff0c;然后重放攻击可以实现&#xff0c;尝试py复现 Python可以正常拿到数据&#xff0c;这题不考请求&#xff0c;这题的难点原来在于数据的加密&#xff0c;这些数字…

什么是301重定向,什么时候应该使用?301重定向详细说明

如果您将网站从一个URL移动到另一个URL&#xff0c;您需要采取必要的步骤来确保您的访问者被发送到正确的位置。在技术领域&#xff0c;这被称为301重定向。 在这里&#xff0c;我们将讨论什么是301重定向&#xff0c;何时需要使用&#xff0c;以及如何在网站或WordPress中重定…

网络流的C++代码实现与过程讲解

网络流是一种非常重要的图论算法,它在许多实际问题中得到广泛应用。本文将介绍网络流算法的C++代码实现与过程讲解。 算法概述 网络流算法是通过将图中的边看作流量通道,将图的点看作流量的起点或终点,来求解图中的最大或最小流量的问题。它是一种非常重要的最优化算法,广…

闲谈跨部门工作

先附上一张网络流传的IT职场江湖图 然后再来探讨一下在工作中如何跨部门沟通&#xff0c;作为一个团队leader&#xff0c;或者团队的核心开发人员&#xff0c;如何有效的跨部门沟通。 在当今快节奏的软件开发行业中&#xff0c;一个公司的组织架构必然是多样化的&#xff0c;多…

15个真正免费的Mac数据恢复软件

由于不同的情况&#xff0c;从Mac或其他存储设备丢失重要文件对我们来说确实是一个巨大的痛苦&#xff0c;但没有人可以避免。现在&#xff0c;您丢失了宝贵的数据&#xff0c;如何找回它&#xff1f; 如果您始终备份数据&#xff0c;则可以从 Time Machine 或其他备份位置恢复…

邮箱签名有什么用?管理员怎么统一设置邮箱签名?

电子邮箱签名能够为个人随意设置&#xff0c;但对企业来说&#xff0c;职工签名代表企业形象&#xff0c;好的公司签名能够反映企业标准化和统一。那样&#xff0c;企业管理员怎样设置统一的签名呢&#xff1f;下面小编将带您深入了解。 一、邮箱签名的功能和作用 在发邮件时…

混合app开发

安卓与h5交互 原生调用js js调用原生 ios与h5交互 代码演示 ios调用h5 xcode创建一个ios项目 h5调用原生 h5部分代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" conten…

pygame 烟花效果

# 初始化 pygame.init() screen_width 800 screen_height 600 screen pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption(烟花效果) # 焰火发射 particles [] # 焰火粒子 def firework(x, y): num_particles 100 # 每次发射的…

华为云服务镜像手动更换

操作步骤&#xff1a; 1、进入华为云首页点击云容器引擎CCE&#xff1b; 2、选择你所要更换镜像的环境【这里以dev环境演示】&#xff1b; 3、点击dev环境后选择顶部的命名空间&#xff0c;点击【工作负载】中右侧栏的【升级】按钮&#xff1b; 4、点【更换镜像】选择你在test…

三级等保安全解决方案——实施方案

实施方案设计 本方案将依照国家有关信息安全建设的一系列法规和政策&#xff0c;为电台建立体系完整、安全功能强健、系统性能优良的网络安全系统。以“统一规划、重点明确、合理建设、逐步强化”为基本指导原则。根据电台网络系统不同信息的重要性调整保护策略&#xff0c;不欠…