Linux多线程编程- 无名信号量
简介
无名信号量(在 POSIX 环境下通常指 sem_t
类型的信号量)是用于同步和互斥的原语,它允许线程和进程按照预期的顺序执行,并确保对共享资源的安全访问。无名信号量与命名信号量的主要区别在于它们的可见性和生命周期。无名信号量通常用于一个进程内的线程间同步,而命名信号量用于多个进程间的同步。
以下是无名信号量的详细介绍:
1. 基础概念:
-
信号量的值:信号量是一个非负整数,通常代表可用的资源数量。例如,信号量值为2意味着有2个资源可用。
-
操作:主要有两种基本操作 -
wait
(或down
、P
)和post
(或up
、V
)。
2. 核心操作:
-
sem_init:用于初始化信号量。需要提供信号量变量的地址、一个标志(指示信号量是否应在多个进程之间共享)以及信号量的初始值。
int sem_init(sem_t *sem, int pshared, unsigned int value);
其中,
pshared
通常设为0,表示此信号量只用于当前进程的线程之间的同步。 -
sem_wait:如果信号量的值大于零,它将减少信号量的值并继续。如果信号量的值为0,调用此操作的线程将被阻塞,直到信号量的值变为正数。
int sem_wait(sem_t *sem);
-
sem_post:增加信号量的值。如果其他线程正在等待此信号量,一个或多个等待线程可能被唤醒。
int sem_post(sem_t *sem);
-
sem_destroy:销毁信号量,释放与其关联的任何资源。
int sem_destroy(sem_t *sem);
3. 使用场景:
-
互斥访问:当多个线程需要访问共享资源,但我们希望一次只有一个线程可以访问时,可以使用信号量。例如,访问一个共享文件或更新一个共享数据结构。
-
条件同步:例如,一个线程生产数据,另一个线程消费数据。消费者线程可能需要等待,直到生产者线程生产了足够的数据。
4. 注意事项:
-
虽然无名信号量通常用于线程间同步,但在某些平台和实现中,它们也可以用于进程间同步,只要这些进程共享同一个信号量变量。
-
使用
sem_destroy
之前,确保没有线程等待该信号量。否则,行为可能是未定义的。 -
与所有同步原语一样,使用信号量需要谨慎,以避免死锁和竞态条件。
总的来说,无名信号量是一种非常有用的同步工具,它提供了一种简单、有效的方法来协调线程的行为和确保对共享资源的安全访问。
示例
以下是一个使用 POSIX 无名信号量进行线程间同步的例子。在这个例子中,我们有两个线程:生产者和消费者。生产者线程生成数据,消费者线程消费它。我们使用信号量来确保生产者产生数据后消费者才开始消费。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>sem_t sem_producer, sem_consumer;#define DATA_SIZE 5
int buffer[DATA_SIZE];
int index = 0;void* producer(void* arg) {for (int i = 0; i < DATA_SIZE; i++) {sem_wait(&sem_producer); // Wait until there is a spot available.buffer[index++] = i; // Produce data.printf("Produced %d\n", i);sem_post(&sem_consumer); // Signal that data has been produced.}return NULL;
}void* consumer(void* arg) {for (int i = 0; i < DATA_SIZE; i++) {sem_wait(&sem_consumer); // Wait until data is available.int data = buffer[--index]; // Consume data.printf("Consumed %d\n", data);sem_post(&sem_producer); // Signal that a spot is free.}return NULL;
}int main() {pthread_t tid1, tid2;// Initialize semaphoressem_init(&sem_producer, 0, DATA_SIZE); // Initially, DATA_SIZE spots are available.sem_init(&sem_consumer, 0, 0); // Initially, no data is available to consume.pthread_create(&tid1, NULL, producer, NULL);pthread_create(&tid2, NULL, consumer, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);sem_destroy(&sem_producer);sem_destroy(&sem_consumer);return 0;
}
在上面的例子中:
sem_producer
信号量表示可用的缓冲区槽位数量。开始时,所有槽位都是可用的。sem_consumer
信号量表示可供消费的数据数量。开始时没有数据可供消费。
生产者每次生产一个数据项前都会等待一个可用的槽位,消费者在每次消费前都会等待可供消费的数据。
运行结果如下:
Produced 0
Consumed 0
Produced 1
Consumed 1
Produced 2
Consumed 2
Produced 3
Consumed 3
Produced 4
Consumed 4
(从另一个视角看这个程序)
以下是生产者和消费者线程共享的资源:
-
变量:
buffer[]
:这是一个整数数组,用于存储生产者产生的数据和消费者消费的数据。index
:这是一个整数,表示buffer[]
中的下一个可用位置或要被消费的数据位置。sem_producer
和sem_consumer
:这是我们用于同步的无名信号量。一个表示有多少空的槽位可用来存储数据,另一个表示有多少数据可供消费。
-
无名信号量:我们使用
sem_init
初始化了两个无名信号量。由于这两个信号量是在主进程的地址空间内初始化的,它们可以被该进程内的所有线程(在这里,是生产者和消费者线程)访问和操作。
关于线程和进程:
-
进程:在这个程序中,主函数
main()
运行在主进程中。所有的全局变量、函数、和在main()
函数内定义的局部变量都在这个进程的地址空间内。 -
线程:我们使用
pthread_create()
创建了两个线程。这两个线程(生产者和消费者)都在上述的主进程内运行。因此,它们共享上述的主进程的地址空间,这也就是为什么它们可以访问和操作同样的变量和无名信号量。
总结:这个程序中只有一个进程。在这个进程内,我们创建了两个线程,它们共享同一块地址空间。这也是为什么无名信号量特别适合于线程间的同步:因为所有线程都可以直接访问和操作进程内的同一个无名信号量。
相关文章:
Linux多线程编程- 无名信号量
简介 无名信号量(在 POSIX 环境下通常指 sem_t 类型的信号量)是用于同步和互斥的原语,它允许线程和进程按照预期的顺序执行,并确保对共享资源的安全访问。无名信号量与命名信号量的主要区别在于它们的可见性和生命周期。无名信号…...

【网络协议】聊聊DHCP和PXE 工作原理
DHCP 动态主机配置协议 对于每个主机来说,只要连接了网络,那么就会配置一个IP地址,那么这个IP地址,如果是手动配置的话,对于公司内部的人员来说都要找IT进行配置,这个太浪费人力物力了,所以解决…...

发现国内优秀的团队协作软件,帮助提高工作效率
中国有许多优秀的团队协作软件,它们在企业和组织中发挥着重要作用。 以下是一些最受欢迎的团队协作软件: 1、钉钉(DingTalk): 这是一款由阿里巴巴推出的企业级协作工具,旨在帮助企业和组织实现高效沟通和协作。钉钉提…...
LeetCode 面试题 08.12. 八皇后
文章目录 一、题目二、C# 题解 一、题目 设计一种算法,打印 N 皇后在 N N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。 注意&#…...

Excel 的下拉列表
可以将 Sheet6 隐藏,就更好地隐藏了来源。...

基于Effect的组件设计 | 京东云技术团队
Effect的概念起源 从输入输出的角度理解Effect https://link.excalidraw.com/p/readonly/KXAy7d2DlnkM8X1yps6L 编程中的Effect起源于函数式编程中纯函数的概念 纯函数是指在相同的输入下,总是产生相同的输出,并且没有任何副作用(side effect)的函数。…...
541. 反转字符串 II
541. 反转字符串 II class Solution { public:void Reverse(string& s, int start, int end){end--;while (start < end){swap(s[start], s[end]);start;end--;}}string reverseStr(string s, int k){int len s.size();for (int i 0; i < len; i 2 * k){if (i …...

基本分段存储管理方式(分段,段表,地址转换以及与分页管理对比)
1.分段 1.进程的地址空间: 按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名 (在低级语言中,程序员使用段名来编程),每段从0开始编址. 2.内存分配规则: 以段为单位进行分配,每个段在内存中占据…...

哪个牌子的洗地机好用?2023洗地机推荐
洗地机作为一款高效的清洁家电能轻松的搞定各种干湿垃圾,满足日常生活中的各种地面清洁需求,越来越受大众的青睐,那么我们如何快速的选择一款适合自己无线洗地机呢?一起来看看! 做推荐之前,先给大家科普选购洗地机的时候应该关注…...

根据脑图谱获取感兴趣区域的mask
根据脑图谱获取感兴趣区域的mask 1,引入1.1 ASPECT-Atlas 2,获取脑图谱感兴趣区域mask参考: 1,引入 脑影像分析中,我们常常会针对性的对某些感兴趣区域进行分析,而对它们进行分析的前提是获取该区域的mask…...

Android Framework通信:Handler
文章目录 前言一、Handler源码分析1、创建Handler2、发送消息3、取消息4、消息处理5、线程切换的方法(Handler异步消息处理机制流程)handler.sendMessage()handler.post()View.post()Activity中的runOnUiThread() 二、Handler高频面试题1、为什么要有Han…...

Redis的安装和配置
一、Redis的安装 使用命令将redis安装到linux服务器 yum -y install redis配置redis配置文件 redis的配置文件默认路径为/etc/redis.conf,对配置文件进行修改。 (1)注释掉bind 127.0.0.1; bind配置项设置的是redis允许的ip地址访问…...

Java武侠文字游戏
import java.util.Random;public class Role {//姓名private String name;//血量private int blood;//性别private char gender;//长相(随机)private String face;String[] boyfaces {"风流俊雅", "气宇轩昂", "相貌英俊", "五官端正"…...

数字化时代下,汽车行业如何突破现有营销困境?
之前三年的“口罩”时期,给全球和中国汽车市场带来不小影响,汽车销售市场整体下滑,传统营销模式很难适应现阶段汽车营销需求,那么在当下,汽车行业应该如何突破现有营销困境呢?接下来就由媒介盒子跟大家聊聊…...

19 | 如何搞清楚事务、连接池的关系?正确配置是怎样的
事务的基本原理 在学习 Spring 的事务之前,你首先要了解数据库的事务原理,我们以 MySQL 5.7 为例,讲解一下数据库事务的基础知识。 我们都知道 当 MySQL 使用 InnoDB 数据库引擎的时候,数据库是对事务有支持的。而事务最主要的作…...

备忘录模式-撤销功能的实现
在idea写代码的过程中,会经常用到一个快捷键——“crtl z”,即撤销功能。“备忘录模式”则为撤销功能提供了一个设计方案。 1 备忘录模式 备忘录模式提供一种状态恢复机制。在不破坏封装的前提下,捕获对象内部状态并在该对象之外保存这个状态。可以在…...

C++入门(二)
文章目录 一、缺省参数1、概念2、缺省参数分类1、全缺省参数2、半缺省参数 3、特性总结 二、函数重载1、引入函数重载2、函数重载概念3、函数重载分类4、C支持函数重载的原理--名字修饰(name Mangling) 三、 引用1、引用概念2、引用特性3、 常引用4、 使用场景1、做参数2、做返…...

【软件设计师】面向对象类图的六种关系
面向对象类图的六种关系(继承、实现、依赖、关联、聚合、组合) 1、泛化(继承)2、实现3、依赖4、关联5、聚合6、组合 面向对象类图的六种关系(继承、实现、依赖、关联、聚合、组合) 进行面向对象设计时&…...

二十七、【四种蒙版】
文章目录 图层蒙版剪贴蒙版快速蒙版矢量蒙版 图层蒙版 在当前图层加上蒙版,黑色画笔的可以让当前图层消失,白色的画笔可以让当前图层出现: 无论填充什么样的颜色,蒙板只有黑白灰三种颜色。模板最简单应用就是我们在插入图形的时候…...
卡尔曼家族从零解剖-(00)目录最新无死角讲解
讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的 卡尔曼家族从零解剖 链接 :卡尔曼家族从零解剖-(00)目录最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/133846882 文末正下方中心提供了本人 联系…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...