Linux多线程编程- 无名信号量

简介

无名信号量(在 POSIX 环境下通常指 sem_t 类型的信号量)是用于同步和互斥的原语,它允许线程和进程按照预期的顺序执行,并确保对共享资源的安全访问。无名信号量与命名信号量的主要区别在于它们的可见性和生命周期。无名信号量通常用于一个进程内的线程间同步,而命名信号量用于多个进程间的同步。

以下是无名信号量的详细介绍:

1. 基础概念

  • 信号量的值:信号量是一个非负整数,通常代表可用的资源数量。例如,信号量值为2意味着有2个资源可用。

  • 操作:主要有两种基本操作 - wait(或 downP)和 post(或 upV)。

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;
}

在上面的例子中:

  1. sem_producer 信号量表示可用的缓冲区槽位数量。开始时,所有槽位都是可用的。
  2. sem_consumer 信号量表示可供消费的数据数量。开始时没有数据可供消费。

生产者每次生产一个数据项前都会等待一个可用的槽位,消费者在每次消费前都会等待可供消费的数据。

运行结果如下:

Produced 0
Consumed 0
Produced 1
Consumed 1
Produced 2
Consumed 2
Produced 3
Consumed 3
Produced 4
Consumed 4

(从另一个视角看这个程序)

以下是生产者和消费者线程共享的资源:

  1. 变量

    • buffer[]:这是一个整数数组,用于存储生产者产生的数据和消费者消费的数据。
    • index:这是一个整数,表示buffer[]中的下一个可用位置或要被消费的数据位置。
    • sem_producersem_consumer:这是我们用于同步的无名信号量。一个表示有多少空的槽位可用来存储数据,另一个表示有多少数据可供消费。
  2. 无名信号量:我们使用sem_init初始化了两个无名信号量。由于这两个信号量是在主进程的地址空间内初始化的,它们可以被该进程内的所有线程(在这里,是生产者和消费者线程)访问和操作。

关于线程和进程:

  • 进程:在这个程序中,主函数main()运行在主进程中。所有的全局变量、函数、和在main()函数内定义的局部变量都在这个进程的地址空间内。

  • 线程:我们使用pthread_create()创建了两个线程。这两个线程(生产者和消费者)都在上述的主进程内运行。因此,它们共享上述的主进程的地址空间,这也就是为什么它们可以访问和操作同样的变量和无名信号量。

总结:这个程序中只有一个进程。在这个进程内,我们创建了两个线程,它们共享同一块地址空间。这也是为什么无名信号量特别适合于线程间的同步:因为所有线程都可以直接访问和操作进程内的同一个无名信号量。

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

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

相关文章

基本分段存储管理方式(分段,段表,地址转换以及与分页管理对比)

1.分段 1.进程的地址空间: 按照程序自身的逻辑关系划分为若干个段&#xff0c;每个段都有一个段名 &#xff08;在低级语言中&#xff0c;程序员使用段名来编程&#xff09;&#xff0c;每段从0开始编址. 2.内存分配规则: 以段为单位进行分配&#xff0c;每个段在内存中占据…

学习笔记---超基础+详细+新手的顺序表~~

目录 1.顺序表的前言 1.1 顺序表--->通讯录&#x1f4c7; 1.2 数据结构的相关概念&#x1f3c7; 1.2.1 什么是数据结构 1.2.1 为什么需要数据结构 2. 顺序表概念及分类 2.1 顺序表的概念&#x1f419; 2.2 顺序表的分类&#x1f42b; 2.2.1 顺序表和数组的区别 2.…

金x软件有限公司安全测试岗位面试

目录 一、自我介绍 二、你是网络空间安全专业的&#xff0c;那你介绍下网络空间安全这块主要学习的东西&#xff1f; 三、本科专业是网络工程&#xff0c;在嘉兴海视嘉安智城科技有限公司实习过&#xff0c;你能说下干的工作吗&#xff1f;&#xff08;没想到问的是本科实习…

第一个Spring程序

目录 一、怎么创建Spring项目 1.1 使用maven创建Spring项目 1.2 导入Spring相关依赖 二、Spring的配置文件 三、使用Spring配置文件创建类对象 3.1 Spring核心api 3.2 Spring程序开发 一、怎么创建Spring项目 1.1 使用maven创建Spring项目 在创建新项目的时候使用maven去创建…

DDoS检测防御实现方案

流量采集模式 通过分光器将流量直接镜像到攻击检测器&#xff0c;收包采用DPDK库。 当前整机流量、源IP信息、连接数 、连接内容(五元组等)的信息汇聚 当发生告警时采样原始数据包&#xff0c; 采用固定采样算法 基于检测对象的TCP syn ack psh ack established的个数、流量…

系统架构师备考倒计时19天(每日知识点)

软件架构评估&#xff08;ATAM&#xff09; 在SAAM的基础上发展起来的&#xff0c;主要针对性能、实用性、安全性和可修改性&#xff0c;在系统开发之前&#xff0c;对这些质量属性进行评价和折中。ATAM方法的主要活动领域包括&#xff1a; 第一阶段 场景和需求收集 收集场景…

NLP算法面经 | 腾讯 VS 美团

作者 | 曾同学 编辑 | NewBeeNLP 面试锦囊之面经分享系列&#xff0c;持续更新中 后台回复『面试』加入讨论组交流噢 lz从3月初脚因打球扭伤了开始&#xff0c;投递简历&#xff0c;接二连三的面试鞭尸又面试&#xff0c;昨天才终于上岸了&#xff0c;分享经验~ 腾讯PCG看点&…

动态规划-买卖股票系列

121.买卖股票的最佳时机 Python: class Solution(object):def maxProfit(self, prices):""":type prices: List[int]:rtype: int"""if len(prices)0:return 0dplen(prices)*[0]minpriceint(prices[0])for i in range (1,len(prices)):minprice…

element plus 的图片上传组件回显

element图片回显是通过修改file-list属性的url属性实现的。 <!-- 图片上传 --><el-form-item label"景区图片" prop"s_img"><el-uploadlist-type"picture-card":action"网址":on-change"handleChange":befor…

【Python-Django】基于TF-IDF算法的医疗推荐系统复现过程

复现步骤 step1&#xff1a; 修改原templates路径&#xff0c;删除&#xff0c;将setting.py中的路径置空 step2&#xff1a; 注册app python manage.py startapp [app名称]在app目录下创建static和templates目录 step3&#xff1a; 将项目中的资源文化进行拷贝 step4&#…

新能源电池试验中准确模拟高空环境大气压力的解决方案

摘要&#xff1a;针对目前新能源电池热失控和特性研究以及生产中缺乏变环境压力准确模拟装置、错误控制方法造成环境压力控制极不稳定以及氢燃料电池中氢气所带来的易燃易爆问题&#xff0c;本文提出了相应的解决方案。方案的关键一是采用了低漏率电控针阀作为下游控制调节阀实…

《省级国土空间规划编制技术规程》国家标准(GB/T 43214-2023)原文下载

《省级国土空间规划编制技术规程》国家标准&#xff08;GB/T 43214-2023&#xff0c;以下简称《规程》&#xff09;&#xff0c;将于2024年1月1日起实施&#xff0c;该《规程》由市场监管总局&#xff08;国家标准委&#xff09;9月7日批准发布。 《规程》由自然资源部组织编制…

Steam将强制执行短信验证以遏制肆虐的恶意更新

为应对最近爆发的恶意更新&#xff0c;著名游戏平台Steam出品方Valve近日发布公告称&#xff0c;将为Steam 上发布游戏的开发者实施额外的安全措施&#xff0c;包括基于短信的确认码。 游戏及软件开发商在 Steam 平台上分发其产品需要用到Steamworks&#xff0c;它支持DRM&…

GEO生信数据挖掘(九)WGCNA分析

第六节&#xff0c;我们使用结核病基因数据&#xff0c;做了一个数据预处理的实操案例。例子中结核类型&#xff0c;包括结核&#xff0c;潜隐进展&#xff0c;对照和潜隐&#xff0c;四个类别。第七节延续上个数据&#xff0c;进行了差异分析。 第八节对差异基因进行富集分析。…

LeetCode 260. 只出现一次的数字 III:异或

【LetMeFly】260.只出现一次的数字 III 力扣题目链接&#xff1a;https://leetcode.cn/problems/single-number-iii/ 给你一个整数数组 nums&#xff0c;其中恰好有两个元素只出现一次&#xff0c;其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返…

数据分析案例-基于snownlp模型的MatePad11产品用户评论情感分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Android 内容提供者和内容观察者:数据共享和实时更新的完美组合

任务要求 一个作为ContentProvider提供联系人数据另一个作为Observer监听联系人数据的变化&#xff1a; 1、创建ContactProvider项目&#xff1b; 2、在ContactProvider项目中用Sqlite数据库实现联系人的读写功能&#xff1b; 3、在ContactProvider项目中通过ContentProvid…

深度学习-卷积神经网络

文章目录 应用卷积神经网络卷积处理分类问题 应用 图片分类图片检索图片分割图片风格迁移姿态估计OCR等 卷积神经网络 核概念计算机视觉中处理图片的核大小是通过经验得来的&#xff0c;而深度学习中的权重大小是自己学习出的。卷积VS神经网络&#xff1a;一个是局部观察一个…

Go-Python-Java-C-LeetCode高分解法-第十周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 我搜集到了50道精选题&#xff0c;适合速成概览大部分常用算法 突…

【基于windows desktop上的docker配置nacos,并采用宿主机访问】

1、拉取镜像&#xff08;以下命令全部基于powershell&#xff09; docker pull nacos/nacos-server2、启动容器 docker run -d -e PREFER_HOST_MODEhostname -e MODEstandalone -e JVM_XMS256m -e JVM_XMX256m -e JVM_XMN128m -p 8848:8848 --name nacos --restartalways nac…