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、概念 原子操作:不可中断的一个或者一系列的操作,即一件事要么做要么不做。临界资源:不同进程能够看到的一份公共资源,一次只能被一个进程使用。PV操作:由于信号量只能进行两种操作等待和发…...
Oracle索引问题汇总
一、oracle 数据库TIMESTAMP 时间字段,设置索引后,通过该字段进行排序,索引排序不生效问题 1. 记录下在工作中遇到的一次索引问题 问题描述: 数据库:oracle; 日志记录表中的一个创建时间(create…...
基于QT用工厂模式实现串口通信与网络通信激光器的控制
配置文件网络配置:IP+Port 串口配置:端口号+波特率 首先,我们需要创建一个配置文件 config.ini,内容如下: [SerialLaser] portName = COM1 baudRate = 9600[NetworkLaser] ipAddress = 192.168.1.1 port = 1234两类激光器的实现: #include <QCoreApplicat…...
【代码随想录Day58】图论Part09
dijkstra(堆优化版)精讲 题目链接/文章讲解:代码随想录 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模糊匹配,如果页面输入_或者%,可以查出所有数据。 (1) SELECT * FROM test WHERE sfsc N and zdzwm like %%% (2) SELECT * FROM test WHERE sfsc N and zdzwm like %_% 2、解决方案 (1)mysql数据库 加转义字…...
【Python】转换得到图片的rgb565格式数据
使用方法:首先在代码同级目录创建input_images文件夹,然后将需要转换的图片放进去。 然后根据你的需要,修改代码最下面的crop_size、resize以及file_name。 最后点击运行,即可得到图片的rgb565格式数据 from PIL import Image, I…...
隨筆 20241024 Kafka中的ISR列表:分区副本的族谱
在分布式系统中,数据的一致性和可靠性至关重要。Apache Kafka作为一个强大的流处理平台,利用其分区和副本机制来确保这些特性。在Kafka中,ISR(In-Sync Replicas)列表是一个关键概念,它用来追踪与领导者副本…...
【python】爬虫
下载与批量下载 import requests #第三方库,没有下载的下载一下 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、列表截取 列表截取:List.slice(start, end),左闭右开 var dataList [1,2,3,4,5,6] var resultList dataList.slice(0…...
ECharts 折线图 / 柱状图 ,通用配置标注示例
option {tooltip: { // 关于提示框(tooltip)的配置// 显示某一个去掉trigger: axis,显示一起显示 trigger: axistrigger: axis},legend: {top: bottom, // 显示标注位置// textStyle: {// color: "#000", // 设置图例文字颜…...
统计数据集的TXT、XML及JSON标注文件中各类别/每个标签的数量
在计算机视觉和深度学习领域,标注文件是模型训练的重要组成部分。无论是图像分类、目标检测还是图像分割,正确的标注能够显著提升模型的性能。在实际应用中,我们需要快速了解每个类别的样本数量,以便进行数据分析、平衡类别分布或…...
Facebook登录客户追踪:了解用户访问路径,优化客户体验
随着数字化转型的不断加速,精准的客户数据收集和用户行为追踪成为企业提升用户体验和优化业务流程的关键。Facebook登录作为一种便捷的第三方登录方式,已经被广泛应用于各类网站和应用中。它不仅简化了用户的注册与登录流程,还帮助企业获得用…...
NUUO摄像头 debugging_center_utils 远程命令执行漏洞复现
0x01 产品描述: NUUO摄像头是由中国台湾NUUO公司生产的一款网络视频录像机(Network Video Recorder,简称NVR),广泛应用于零售、交通、教育、政府和银行等多个领域。它能够同时管理多个IP摄像头,…...
Nginx 的讲解和案例示范
一、基础理解 1.1 Nginx 是什么? Nginx是一个高性能的 Web 服务器和反向代理服务器,同时也可以作为邮件代理服务器。Nginx 以其高并发处理能力、低内存消耗和丰富的功能受到广泛欢迎。 主要功能: 静态资源服务:高效地提供 HTM…...
微信小程序元素水平居中或垂直居中
最近在做一个微信小程序的项目,其中涉及到css样式实现将<navigator>标签内的图片和文本元素垂直排列,并水平居中。在尝试实现的过程中,将元素在标签内的所有排列情况都顺带实现了。上代码: index.wxml <navigator url&…...
ClickHouse 神助攻:纽约城市公共交通管理(MTA)数据应用挑战赛
本文字数:13198;估计阅读时间:33 分钟 作者:The PME Team 本文在公众号【ClickHouseInc】首发 我们一向对开放数据挑战充满热情,所以当发现 MTA(城市交通管理局)在其官网发起了这样的挑战时&…...
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项目:w…...
使用 Docker Compose 将数据版 LobeChat 服务端部署
LobeChat 是一个基于 TypeScript 的开源聊天机器人项目,支持本地部署和接入多个大语言模型。本文介绍如何使用 Docker Compose 将 LobeChat 服务端及其数据库部署到生产环境,让您拥有一个私有化的、可定制的 AI 聊天助手。 一、部署前准备 服务器&…...
python如何完成金融领域的数据分析,思路以及常见的做法是什么?
引言 在现代金融领域,数据分析已成为决策支持的重要工具。随着金融市场的复杂性和数据量的激增,传统的分析方法已无法满足需求。 Python作为一种强大的编程语言,凭借其丰富的库和工具,成为金融数据分析的首选语言之一。 本文将探讨如何利用Python进行金融数据分析,包括…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化
是不是受够了安装了oracle database之后sqlplus的简陋,无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话,配置.bahs_profile后也能解决上下翻页这些,但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可,…...
Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...
