当前位置: 首页 > news >正文

Linux系统编程——信号量

一、信号量的定义和原理

1、概念

  • 原子操作:不可中断的一个或者一系列的操作,即一件事要么做要么不做。
  • 临界资源:不同进程能够看到的一份公共资源,一次只能被一个进程使用。
  • PV操作:由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

                P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行;
                V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1。


  就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

2、信号量的定义

  为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来调协进程对共享资源的访问的。

3、信号量的原理

1. 测试控制该资源的信号量;

2. 若信号量的值为正,则进程可以使用该资源,进程的信号量值减1,表示一个资源被使用;

3. 若此信号量为0,则进程进入休眠,直到该信号量值大于0;

4. 当进程不再使用一个由一个信号控制的共享资源时,该信号量加1,如果有进程正在休眠等待该信号量,则该进程会被唤醒。

二、信号量的使用

1、一些数据结构的定义

(1)semid_ds

  内核为每个信号量集合维护着一个结构体:

struct semid_ds{struct ipc_perm sem_perm;unsigned short sem_nsems;time_t sem_otime;time_t sem_ctime;...
}

(2)semun(必须定义该联合体)

union semun{int             val;struct semid_ds *buf;unsigned short  *array;
}

(3)sembuf(信号量操作数组)

struct sembuf{// 除非使用一组信号量,否则它为0,一般从0,1,...num_secs-1unsigned short    sem_num; // 信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,// 即P(等待)操作,一个是+1,即V(发送信号)操作。short             sem_op;// 通常为SEM_UNDO,使操作系统跟踪信号,// 并在进程没有释放该信号量而终止时,操作系统释放信号量。short              sem_flg;
}

2、semget函数

#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);

功能:创建一个新信号量集或取得一个已有信号量集。
参数
        key:整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作;
        num_sems:指定需要的信号量数目,它的值几乎总是1;
        sem_flags:一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。
        返回值:成功返回一个相应信号标识符(非零),失败返回-1。

3、semop函数

#include <sys/sem.h>
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);

功能:它的作用是改变信号量的值。
参数
        sem_id:由semget返回的信号量标识符;
        sem_opa:表示一个由sembuf结构表示的信号量操作数组;
        num_sem_ops:规定该数组中操作的数量。
返回值:成功返回0,失败返回-1。

4、semctl函数

#include <sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);

功能:直接控制信号量的信息。
参数
        sem_id:信号量标识符;
        sem_num:信号量的值;
        command:通常是下面两个值中的其中一个:
        SETVAL:用来把信号量初始化为一个已知的值。p 这个值通过union semun中的val成员设置,其作用是在信号量第一次使用前对它进行设置;
        IPC_RMID:用于删除一个已经无需继续使用的信号量标识符。
返回值:成功返回0,失败返回-1。

三、信号量的demo

// comm.h
#ifndef _MYSEM_H_
#define _MYSEM_H_#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>  // ftok
#include <sys/sem.h>
#include <sys/wait.h>
#include <string.h>#define PATHNAME "."  // ftok 中生成key值 . 表示当前路径
#define PROJ_ID  56  // ftok 中配合PATHNAME 生成唯一key值union semun
{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;
};int create_sems(int nums);  // 创建含有nums个信号量的集合
int get_sems();     // 获取信号量
// 初始化semid对应的信号量集中编号为which的信号量值为value
int init_sems(int semid , int which, int value);
int destroy_sems(int semid); // 释放该信号量集
int P(int semid, int which);    // 表示分配 信号量值-1
int V(int semid, int which);    // 表示释放 信号量值+1#endif /* _MYSEM_H_ */
// comm.cpp
#include "comm.h"// 创建信号量和获取信号量公用函数
static int comm_sem(int nums , int semflag)
{// ftok 函数把一个已存在的路径名和一个整数标识转换成一个key_t值,// 即IPC关键字。key_t key = ftok(PATHNAME, PROJ_ID);if(key < 0){perror("ftok");return -1;}// 用来创建一个信号集,或者获取已存在的信号集。int semid = semget(key, nums, semflag); if( semid < 0){perror("semget");return -1;}return semid;
}// 初始化操作数组
static int comm_sem_op(int semid, int which, int op)
{struct sembuf _sembuf;_sembuf.sem_num = which;_sembuf.sem_op = op;_sembuf.sem_flg = 0; //  IPC_NOWAIT  SEM_UNDOreturn semop(semid, &_sembuf, 1);
}// 创建含有nums个信号量的集合
int create_sems(int nums)
{return comm_sem(nums, IPC_CREAT|IPC_EXCL|0666);
}// 初始化信号集
int init_sems(int semid , int which, int value)
{union semun _semun;_semun.val = value;int ret = semctl(semid, which, SETVAL,_semun);if(ret < 0){perror("inin_sem");return -1;}return 0;
}// 获取信号量
int get_sems()    
{return comm_sem(0, IPC_CREAT);
}// 释放该信号量集
int destroy_sems(int semid) 
{int ret = semctl(semid, 0, IPC_RMID, NULL);if(ret < 0){perror("rm_sem");return -1;}return 0;
}// P操作
int P(int semid, int which)    
{return comm_sem_op(semid, which , -1);
}// V操作
int V(int semid, int which)    
{return comm_sem_op(semid, which, 1);
}
// test.cpp
#include "comm.h"
#include <stdio.h>
#include <unistd.h>int main()
{int semid = create_sems(10); // 创建一个包含10个信号量的信号集init_sems(semid, 0, 1);  // 初始化编号为 0 的信号量值为1pid_t id = fork(); // 创建子进程if (id < 0){perror("fork");return -1;}else if (0 == id) // 子进程{ int sem_id = get_sems();while(1){P(sem_id, 0); // 对该信号量集中的0号信号做P操作printf("你");fflush(stdout);sleep(1);printf("好");printf(":");fflush(stdout);sleep(1);V(sem_id, 0);}}else // 父进程{while(1){P(semid,0);printf("在");sleep(1);printf("吗");printf("?");fflush(stdout);V(semid, 0);}wait(NULL);}destroy_sems(semid);return 0;
}

四、信号量的总结

  信号量是一个特殊的变量,程序对其访问都是原子操作,且只允许对它进行等待(即P(信号变量))和发送(即V(信号变量))信息操作。我们经常通过信号来解决多个进程对同一资源的访问竞争的问题,使在任一时刻只能有一个执行线程访问代码的临界区域,也可以说它是协调进程间的对同一资源的访问权,也就是用于同步进程的。

【优点】:可以同步进程。
【缺点】:信号量有限。

相关文章:

Linux系统编程——信号量

一、信号量的定义和原理 1、概念 原子操作&#xff1a;不可中断的一个或者一系列的操作&#xff0c;即一件事要么做要么不做。临界资源&#xff1a;不同进程能够看到的一份公共资源&#xff0c;一次只能被一个进程使用。PV操作&#xff1a;由于信号量只能进行两种操作等待和发…...

Oracle索引问题汇总

一、oracle 数据库TIMESTAMP 时间字段&#xff0c;设置索引后&#xff0c;通过该字段进行排序&#xff0c;索引排序不生效问题 1. 记录下在工作中遇到的一次索引问题 问题描述&#xff1a; 数据库&#xff1a;oracle&#xff1b; 日志记录表中的一个创建时间&#xff08;create…...

基于QT用工厂模式实现串口通信与网络通信激光器的控制

配置文件网络配置:IP+Port 串口配置:端口号+波特率 首先,我们需要创建一个配置文件 config.ini,内容如下: [SerialLaser] portName = COM1 baudRate = 9600[NetworkLaser] ipAddress = 192.168.1.1 port = 1234两类激光器的实现: #include <QCoreApplicat…...

【代码随想录Day58】图论Part09

dijkstra&#xff08;堆优化版&#xff09;精讲 题目链接/文章讲解&#xff1a;代码随想录 import java.util.*;class Edge {int to; // 邻接顶点int val; // 边的权重Edge(int to, int val) {this.to to;this.val val;} }class Pair<U, V> {public final U first; …...

_或者%关键字模糊匹配查出所有数据

1、问题 sql模糊匹配&#xff0c;如果页面输入_或者%&#xff0c;可以查出所有数据。 (1) SELECT * FROM test WHERE sfsc N and zdzwm like %%% (2) SELECT * FROM test WHERE sfsc N and zdzwm like %_% 2、解决方案 &#xff08;1&#xff09;mysql数据库 加转义字…...

【Python】转换得到图片的rgb565格式数据

使用方法&#xff1a;首先在代码同级目录创建input_images文件夹&#xff0c;然后将需要转换的图片放进去。 然后根据你的需要&#xff0c;修改代码最下面的crop_size、resize以及file_name。 最后点击运行&#xff0c;即可得到图片的rgb565格式数据 from PIL import Image, I…...

隨筆 20241024 Kafka中的ISR列表:分区副本的族谱

在分布式系统中&#xff0c;数据的一致性和可靠性至关重要。Apache Kafka作为一个强大的流处理平台&#xff0c;利用其分区和副本机制来确保这些特性。在Kafka中&#xff0c;ISR&#xff08;In-Sync Replicas&#xff09;列表是一个关键概念&#xff0c;它用来追踪与领导者副本…...

【python】爬虫

下载与批量下载 import requests #第三方库&#xff0c;没有下载的下载一下 pip install requests#爬虫下载图片 resrequests.get("url") print(res.content)#二进制字节流#写文件 with open("beauty.jpg","wb")as f:f.write(res.content)#批量…...

大语言模型数据类型与环境安装(llama3模型)

文章目录 前言一、代码获取一、环境安装二、大语言模型数据类型1、基本文本指令数据类型2、数学指令数据类型3、几何图形指令数据类型4、多模态指令数据类型5、翻译指令数据类型三、vscode配置四、相关知识内容1、理解softmax内容2、torch相关函数nn.Embedding函数torch.nn.fun…...

JS:列表操作

目录 1、列表截取2、列表数据包含3、列表筛选4、极值操作5、获取列表对象某一属性构建列表6、获取元素在列表中的下标7、列表去重 1、列表截取 列表截取&#xff1a;List.slice(start, end)&#xff0c;左闭右开 var dataList [1,2,3,4,5,6] var resultList dataList.slice(0…...

ECharts 折线图 / 柱状图 ,通用配置标注示例

option {tooltip: { // 关于提示框&#xff08;tooltip&#xff09;的配置// 显示某一个去掉trigger: axis&#xff0c;显示一起显示 trigger: axistrigger: axis},legend: {top: bottom, // 显示标注位置// textStyle: {// color: "#000", // 设置图例文字颜…...

统计数据集的TXT、XML及JSON标注文件中各类别/每个标签的数量

在计算机视觉和深度学习领域&#xff0c;标注文件是模型训练的重要组成部分。无论是图像分类、目标检测还是图像分割&#xff0c;正确的标注能够显著提升模型的性能。在实际应用中&#xff0c;我们需要快速了解每个类别的样本数量&#xff0c;以便进行数据分析、平衡类别分布或…...

Facebook登录客户追踪:了解用户访问路径,优化客户体验

随着数字化转型的不断加速&#xff0c;精准的客户数据收集和用户行为追踪成为企业提升用户体验和优化业务流程的关键。Facebook登录作为一种便捷的第三方登录方式&#xff0c;已经被广泛应用于各类网站和应用中。它不仅简化了用户的注册与登录流程&#xff0c;还帮助企业获得用…...

NUUO摄像头 debugging_center_utils 远程命令执行漏洞复现

0x01 产品描述&#xff1a; ‌ NUUO摄像头‌是由中国台湾NUUO公司生产的一款网络视频录像机&#xff08;Network Video Recorder&#xff0c;简称NVR&#xff09;&#xff0c;广泛应用于零售、交通、教育、政府和银行等多个领域。它能够同时管理多个IP摄像头&#xff0c…...

Nginx 的讲解和案例示范

一、基础理解 1.1 Nginx 是什么&#xff1f; Nginx是一个高性能的 Web 服务器和反向代理服务器&#xff0c;同时也可以作为邮件代理服务器。Nginx 以其高并发处理能力、低内存消耗和丰富的功能受到广泛欢迎。 主要功能&#xff1a; 静态资源服务&#xff1a;高效地提供 HTM…...

微信小程序元素水平居中或垂直居中

最近在做一个微信小程序的项目&#xff0c;其中涉及到css样式实现将<navigator>标签内的图片和文本元素垂直排列&#xff0c;并水平居中。在尝试实现的过程中&#xff0c;将元素在标签内的所有排列情况都顺带实现了。上代码&#xff1a; index.wxml <navigator url&…...

ClickHouse 神助攻:纽约城市公共交通管理(MTA)数据应用挑战赛

本文字数&#xff1a;13198&#xff1b;估计阅读时间&#xff1a;33 分钟 作者&#xff1a;The PME Team 本文在公众号【ClickHouseInc】首发 我们一向对开放数据挑战充满热情&#xff0c;所以当发现 MTA&#xff08;城市交通管理局&#xff09;在其官网发起了这样的挑战时&…...

ELK + Filebeat + Spring Boot:日志分析入门与实践(二)

目录 一、环境 1.1 ELKF环境 1.2 版本 1.3 流程 二、Filebeat安装 2.1 安装 2.2 新增配置采集日志 三、logstash 配置 3.1 配置输出日志到es 3.2 Grok 日志格式解析 3.2 启动 logstash ​3.3 启动项目查看索引 一、环境 1.1 ELKF环境 springboot项目&#xff1a;w…...

使用 Docker Compose 将数据版 LobeChat 服务端部署

LobeChat 是一个基于 TypeScript 的开源聊天机器人项目&#xff0c;支持本地部署和接入多个大语言模型。本文介绍如何使用 Docker Compose 将 LobeChat 服务端及其数据库部署到生产环境&#xff0c;让您拥有一个私有化的、可定制的 AI 聊天助手。 一、部署前准备 服务器&…...

python如何完成金融领域的数据分析,思路以及常见的做法是什么?

引言 在现代金融领域,数据分析已成为决策支持的重要工具。随着金融市场的复杂性和数据量的激增,传统的分析方法已无法满足需求。 Python作为一种强大的编程语言,凭借其丰富的库和工具,成为金融数据分析的首选语言之一。 本文将探讨如何利用Python进行金融数据分析,包括…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

Web 架构之 CDN 加速原理与落地实践

文章目录 一、思维导图二、正文内容&#xff08;一&#xff09;CDN 基础概念1. 定义2. 组成部分 &#xff08;二&#xff09;CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 &#xff08;三&#xff09;CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 &#xf…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型&#xff08;Primitive&#xff09; 和 对象类型&#xff08;Object&#xff09; 两大类&#xff0c;共 8 种&#xff08;ES11&#xff09;&#xff1a; 一、原始类型&#xff08;7种&#xff09; 1. undefined 定…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Modbus RTU与Modbus TCP详解指南

目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...