《Linux系统编程篇》System V信号量(Linux 进程间通信(IPC))——基础篇

文章目录

    • 引言
    • 🧑‍🏫 **Linux 中的 System V 信号量:基础与实战**
      • 🌟 **System V 信号量简介**
      • 🔑 **关键概念**
      • 🛠️ **System V 信号量的相关函数**
      • 📜 **函数原型**
        • 1. `semget()` — 创建或获取信号量集
        • 2. `semop()` — 执行信号量操作
        • 3. `semctl()` — 控制信号量集
        • 4. `semctl()` — 删除信号量集
      • 💡 **示例:基本的信号量操作**
      • 🔍 **解析**
      • 🧐 **进阶实例:生产者-消费者问题**
      • 📝 **总结:**

切勿好高骛远,任何大事,都是一砖一瓦垒起来的 ——家驹(StrangeHead)

引言

上一篇文章我们知道了什么是信号,以及如何使用POSIX信号量,什么是P操作,什么是V操作,了解过Linux进化史的小伙伴就知道,POSIX是Unix的一个标准规范(Unix及其衍生系统遵循的一系列标准的集合),而System V也只不过是别家公司基于Linux写的另一套信号量罢了。回顾一下上一节的知识,接下来这一节对你来说简直是轻松驾驭!

🧑‍🏫 Linux 中的 System V 信号量:基础与实战

在并发编程中,尤其是在多进程环境下,资源共享是一个常见问题。为了避免多个进程同时访问某个共享资源,导致数据不一致或系统崩溃,System V 信号量应运而生!信号量是一种原始的同步机制,可以在多个进程间进行通信和控制资源访问。


🌟 System V 信号量简介

System V 信号量(sem_t)是 Unix/Linux 系统中一种进程间同步和互斥的机制。它们通常用于解决 互斥(保证一次只有一个进程访问资源)和 同步(控制多个进程的执行顺序)问题。

🔑 关键概念

  1. 信号量集:每个信号量都是一个整数,表示某一资源的可用数量。多个信号量可以组合在一起形成一个信号量集。
  2. P 操作(等待):用于请求资源,减少信号量。如果信号量为 0,进程会阻塞,直到资源可用。
  3. V 操作(释放):用于释放资源,增加信号量,并唤醒一个被阻塞的进程。

🛠️ System V 信号量的相关函数

系统提供了几个关键的函数来操作信号量。它们分别是:

  1. semget() – 获取信号量集的标识符。
  2. semctl() – 控制信号量集的属性。
  3. semop() – 执行信号量操作(P 操作和 V 操作)。
  4. semctl() – 删除信号量集。

📜 函数原型

1. semget() — 创建或获取信号量集
int semget(key_t key, int nsems, int semflg);

示例:

int sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);

这将创建一个包含 1 个信号量的信号量集,并将其标识符保存在 sem_id 中。信号量集权限为 0666,表示所有用户均可读写。

  • key: 信号量集的标识符,通常用 IPC_PRIVATE 表示创建一个新的信号量集,或者指定一个特定的键值。
  • nsems: 信号量集的数量,即信号量的个数。
  • semflg: 权限标志,通常使用 IPC_CREAT 来创建一个新的信号量集,或者使用 IPC_EXCL 保证不会与已有的信号量集冲突。

IPC_CREAT:创建一个新的信号量集。
IPC_EXCL:如果信号量集已经存在,返回错误。
0666:信号量集的权限,类似文件权限。

  • 返回值:返回一个信号量集的标识符。
  • 失败时,返回 -1,并设置 errno。
2. semop() — 执行信号量操作
int semop(int semid, struct sembuf *sops, size_t nsops);

示例:

struct sembuf sops;
sops.sem_num = 0;   // 第一个信号量
sops.sem_op = -1;   // P 操作(减 1,表示请求资源)
sops.sem_flg = 0;if (semop(sem_id, &sops, 1) == -1) {perror("semop");exit(1);
}

该代码会让当前进程等待,直到第一个信号量的值大于 0。

  • semid: 信号量集的标识符。

  • sops: 指向一个 struct sembuf 数组的指针,表示一系列信号量操作。每个 sops 包含:

    • sem_num:操作的信号量编号,表示要操作的信号量。

    • sem_op:操作类型:

      • -1:P 操作,减少信号量(等待资源)。
      • 1:V 操作,增加信号量(释放资源)。
    • sem_flg:通常为 0,表示没有额外标志。

  • nsops: 操作的数量。

  • 返回值:成功时返回 0,失败时返回 -1。

  • 失败时,返回 -1,并设置 errno。

3. semctl() — 控制信号量集
int semctl(int semid, int semnum, int cmd, ...);

示例:

// 设置信号量的初始值
if (semctl(sem_id, 0, SETVAL, 1) == -1) {perror("semctl");exit(1);
}// 获取信号量的值
int val = semctl(sem_id, 0, GETVAL);
if (val == -1) {perror("semctl");exit(1);
}
printf("信号量值为:%d\n", val);
  • semid: 信号量集标识符。
  • semnum: 信号量的编号。如果是对整个信号量集进行操作,可以传入 0。
  • cmd: 控制命令,常用命令有:
    • IPC_RMID:删除信号量集。
    • GETVAL:获取信号量当前的值。
    • SETVAL:设置信号量的值。

返回值:根据命令不同,返回不同的值。

  • 根据命令不同,返回不同的值。例如,SETVAL 返回旧的信号量值,GETVAL 返回信号量的当前值。
4. semctl() — 删除信号量集

通过 semctl()IPC_RMID 命令删除信号量集。


💡 示例:基本的信号量操作

我们通过一个简单的程序来演示如何创建信号量、执行 P 操作、V 操作,以及如何删除信号量集。

#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <unistd.h>
#include <sys/types.h>int main() {// 创建一个信号量集,包含 1 个信号量int sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);if (sem_id == -1) {perror("semget");exit(1);}// 初始化信号量为 1if (semctl(sem_id, 0, SETVAL, 1) == -1) {perror("semctl");exit(1);}struct sembuf sops;sops.sem_num = 0;   // 使用第一个信号量sops.sem_flg = 0;   // 不使用其他标志位// P 操作:请求资源,信号量减 1sops.sem_op = -1;  // 这里是 P 操作(信号量减 1)if (semop(sem_id, &sops, 1) == -1) {perror("semop");exit(1);}printf("进程 %d 获取资源,开始工作...\n", getpid());sleep(2);  // 模拟处理资源的时间// V 操作:释放资源,信号量加 1sops.sem_op = 1;   // 这里是 V 操作(信号量加 1)if (semop(sem_id, &sops, 1) == -1) {perror("semop");exit(1);}printf("进程 %d 释放资源,结束工作!\n", getpid());// 删除信号量集if (semctl(sem_id, 0, IPC_RMID) == -1) {perror("semctl");exit(1);}return 0;
}

🔍 解析

  1. semget():创建一个信号量集,信号量的数量为 1(即一个资源)。
  2. semctl():初始化信号量的值为 1,表示资源初始状态为可用。
  3. semop():执行 P 操作,使得进程占用资源。若信号量为 0,进程将被阻塞。
  4. sleep(2):模拟进程使用资源的时间。
  5. semop():执行 V 操作,释放资源,将信号量值加 1,唤醒其他等待的进程。
  6. semctl():删除信号量集,释放资源。

🧐 进阶实例:生产者-消费者问题

在这个经典问题中,生产者不断生产资源,消费者不断消费资源,我们使用信号量来控制生产者和消费者的同步。

下一节我们使用System V来实现这个进阶实例


📝 总结:

System V 信号量是 Linux 系统中提供的一种强大的并发控制工具。通过 semget() 创建信号量集,利用 semop() 执行操作,使用 semctl() 控制信号量的值,进程间可以高效地同步和互斥。对于初学者来说,理解信号量的基本操作和应用场景(如生产者-消费者问题)是学习多进程编程的重要一步。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何通过Windows环境远程控制MusicGPT在线生成高质量AI音乐

文章目录 前言1. 本地部署2. 使用方法介绍3. 内网穿透工具下载安装4. 配置公网地址5. 配置固定公网地址 前言 在这个快节奏的时代&#xff0c;音乐不仅是心灵的慰藉&#xff0c;更是创意的源泉。试想一下&#xff0c;在忙碌的工作间隙或悠闲的周末午后&#xff0c;只需轻敲几行…

大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(3)

Paimon的下载及安装&#xff0c;并且了解了主键表的引擎以及changelog-producer的含义参考&#xff1a; 大数据组件(四)快速入门实时数据湖存储系统Apache Paimon(1) 利用Paimon表做lookup join&#xff0c;集成mysql cdc等参考&#xff1a; 大数据组件(四)快速入门实时数据…

Spring面试题2

1、compareable和compactor区别 定义与包位置:Comparable是一个接口&#xff0c;位于java.lang包,需要类去实现接口&#xff1b;而Compactor是一个外部比较器&#xff0c;位于java.util包 用法&#xff1a;Comparable只需要实现int compareTo(T o) 方法&#xff0c;比较当前对…

react(9)-redux

使用CRA快速创建react项目 npx create-react-app react-redux 安装配套工具 npm i reduxjs/toolkit react-redux 启动项目 在创建项目时候会出现一个问题 You are running create-react-app 5.0.0, which is behind the latest release (5.0.1). We no longer support…

HTTP SSE 实现

参考&#xff1a; SSE协议 SSE技术详解&#xff1a;使用 HTTP 做服务端数据推送应用的技术 一句概扩 SSE可理解为&#xff1a;服务端和客户端建立连接之后双方均保持连接&#xff0c;但仅支持服务端向客户端推送数据。推送完毕之后关闭连接&#xff0c;无状态行。 下面是基于…

STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(二)

目录 一、B2121 最长最短单词 - 洛谷 算法代码&#xff1a; 代码分析 变量定义 输入处理 单词长度计算 更新最长和最短单词的长度 输出最长单词 输出最短单词 评测记录&#xff1a;​编辑 二、B2122 单词翻转 - 洛谷 算法代码&#xff1a; 代码分析 引入头文件和定…

74. 搜索二维矩阵(LeetCode 热题 100)

题目来源; 74. 搜索二维矩阵 - 力扣&#xff08;LeetCode&#xff09; 题目内容&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &am…

JUC并发—9.并发安全集合四

大纲 1.并发安全的数组列表CopyOnWriteArrayList 2.并发安全的链表队列ConcurrentLinkedQueue 3.并发编程中的阻塞队列概述 4.JUC的各种阻塞队列介绍 5.LinkedBlockingQueue的具体实现原理 6.基于两个队列实现的集群同步机制 4.JUC的各种阻塞队列介绍 (1)基于数组的阻塞…

SQL Server导出和导入可选的数据库表和数据,以sql脚本形式

一、导出 1. 打开SQL Server Management Studio&#xff0c;在需要导出表的数据库上单击右键 → 任务 → 生成脚本 2. 在生成脚本的窗口中单击进入下一步 3. 如果只需要导出部分表&#xff0c;则选择第二项**“选择具体的数据库对象(Select specific database objects)”**&am…

DDoCT:形态保持的双域联合优化用于快速稀疏视角低剂量CT成像|文献速递-医学影像人工智能进展

Title 题目 DDoCT: Morphology preserved dual-domain joint optimization for fast sparse-view low-dose CT imaging DDoCT&#xff1a;形态保持的双域联合优化用于快速稀疏视角低剂量CT成像 01 文献速递介绍 计算机断层扫描&#xff08;CT&#xff09;是当今广泛应用的…

【Linux】多线程 -> 线程同步与基于BlockingQueue的生产者消费者模型

线程同步 条件变量 当一个线程互斥地访问某个变量时&#xff0c;它可能发现在其它线程改变状态之前&#xff0c;它什么也做不了。 例如&#xff1a;一个线程访问队列时&#xff0c;发现队列为空&#xff0c;它只能等待&#xff0c;直到其它线程将一个节点添加到队列中。这…

WPF的页面设计和实用功能实现

目录 一、TextBlock和TextBox 1. 在TextBlock中实时显示当前时间 二、ListView 1.ListView显示数据 三、ComboBox 1. ComboBox和CheckBox组合实现下拉框多选 四、Button 1. 设计Button按钮的边框为圆角&#xff0c;并对指针悬停时的颜色进行设置 一、TextBlock和TextBox…

Ubuntu24.04LTS的下载安装超细图文教程(VMware虚拟机及正常安装)

&#x1f638;个人主页&#x1f449;&#xff1a;神兽汤姆猫 &#x1f4d6;系列专栏&#xff1a;开发语言环境配置 、 Java学习 、Java面试 、Markdown等 学习上的每一次进步&#xff0c;均来自于平时的努力与坚持。 &#x1f495;如果此篇文章对您有帮助的话&#xff0c;请点…

buu-get_started_3dsctf_2016-好久不见39

栈溢出外平栈 1外平栈与内平栈的区别 外平栈&#xff1a; 栈帧的局部变量和返回地址之间没有额外的对齐或填充。返回地址直接位于局部变量的上方&#xff08;即栈顶方向&#xff09;。在计算偏移时&#xff0c;不需要额外加 4&#xff08;因为返回地址紧邻局部变量&#xff09…

QML Component 与 Loader 结合动态加载组件

在实际项目中&#xff0c;有时候我们写好一个组件&#xff0c;但不是立即加载出来&#xff0c;而是触发某些条件后才动态的加载显示出来&#xff0c;当处理完某些操作后&#xff0c;再次将其关闭掉&#xff1b; 这样的需求&#xff0c;可以使用 Component 包裹着组件&#xff…

vim修改只读文件

现象 解决方案 对于有root权限的用户&#xff0c;在命令行输入 :wq! 即可强制保存退出

UML顺序图的建模方法及应用示例

《UML 2.5基础、建模与设计实践》(李波&#xff0c;姚丽丽&#xff0c;朱慧)【摘要 书评 试读】- 京东图书 顺序图是强调消息时间顺序的交互图&#xff0c;它描述了对象之间传送消息的时间顺序&#xff0c;用于表示用例中的行为顺序。顺序图将交互关系表示为一个二维图&#x…

docker 安装jenkins

使用docker 容器安装jenkins比较方便&#xff0c;但是细节比较重要&#xff0c;这里实战安装了一遍&#xff0c;可用&#xff1a; 拉取最新的jenkins镜像 docker pull jenkins/jenkins 如果没有翻墙的话&#xff0c;可以会有下面的报错&#xff1a; Error response from dae…

My Metronome for Mac v1.4.2 我的节拍器 支持M、Intel芯片

应用介绍 My Metronome 是一款适用于 macOS 的专业节拍器应用程序&#xff0c;旨在帮助音乐家、作曲家、学生和任何需要精确节奏控制的人进行练习。无论是进行乐器练习、音乐创作还是演出排练&#xff0c;My Metronome 都能为用户提供精准的节拍支持和灵活的功能&#xff0c;确…

第1章大型互联网公司的基础架构——1.12 多机房:主备机房

除了要考虑机房内的各个组件&#xff0c;也要考虑机房自身的高可用问题。使用单机房架构搭建互联网应用后台&#xff0c;虽然接入层、业务服务层、存储层均具备高可用架构&#xff0c;但由于机房是单点&#xff0c;所以还是避免不了机房故障会造成整个应用无法访问的问题。可能…