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

C- 使用原子变量实现信号量

信号量

信号量(Semaphore)是并发编程中的一个核心同步原语,它在多进程和多线程环境下被设计用来协调不同的执行单元,确保它们在对共享资源的访问上达到同步和互斥。信号量内部维护一个计数器,该计数器的初始值可以被视为可用资源的数量。当一个进程或线程试图“获取”一个信号量时,该计数器会递减;当它“释放”信号量时,计数器则递增。如果计数器的值达到零,任何试图获取信号量的操作都会被阻塞,直至其他进程或线程释放资源。

信号量通常可以分为两大类:命名信号量(Named Semaphores)和无名信号量(Unnamed Semaphores)。命名信号量是通过一个独特的标识符,在系统级别进行识别的,通常与文件系统上的某个文件关联。这使得不同的进程可以通过这一标识符来定位和操作同一个信号量。而无名信号量主要存在于进程的内存地址空间中,通常用于进程内的线程同步。由于无名信号量仅存在于进程的内存中,因此它们的生命周期与包含它们的进程相同。

为了有效利用信号量,开发者需要深入理解其工作机制和相关的API调用,确保在并发和竞争条件下实现正确、高效的资源访问控制。

实现信号量

实现信号量仅使用原子变量是相对复杂的。以下是一个简单的信号量实现,使用 C11 的 atomic_int

#include <stdio.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <pthread.h>typedef struct {atomic_int value;
} AtomicSemaphore;void AtomicSemaphore_init(AtomicSemaphore* sem, int initial) {atomic_store(&sem->value, initial);
}void AtomicSemaphore_wait(AtomicSemaphore* sem) {int expected;do {while ((expected = atomic_load(&sem->value)) <= 0) {// busy-wait/spin until value is greater than 0}} while (!atomic_compare_exchange_weak(&sem->value, &expected, expected - 1));
}void AtomicSemaphore_post(AtomicSemaphore* sem) {atomic_fetch_add(&sem->value, 1);
}void* test_func(void* arg) {AtomicSemaphore* sem = (AtomicSemaphore*)arg;AtomicSemaphore_wait(sem);printf("Thread %ld acquired the semaphore!\n", pthread_self());AtomicSemaphore_post(sem);return NULL;
}int main() {AtomicSemaphore sem;AtomicSemaphore_init(&sem, 1);  // Initial value set to 1pthread_t threads[10];for (int i = 0; i < 10; i++) {pthread_create(&threads[i], NULL, test_func, &sem);}for (int i = 0; i < 10; i++) {pthread_join(threads[i], NULL);}return 0;
}

注意:

  1. 这个简单的信号量实现使用了"忙等待"或自旋,这可能会导致性能问题,尤其是在高度竞争的情况下。

  2. atomic_compare_exchange_weak 函数尝试将 sem->value 更新为 expected - 1,只有当 sem->value 的当前值与 expected 匹配时才会这样做。如果不匹配,函数将返回 false,并在 expected 中设置当前的 sem->value

  3. 在真实环境中,可能需要考虑使用更复杂的策略(例如,当信号量值为0时,线程进入休眠状态而不是持续自旋)。

  4. 虽然这个实现提供了原子操作的信号量,但它不是传统的信号量,因为它并不提供线程阻塞功能。这意味着当信号量的值为0时,线程将持续自旋,直到它可以获取信号量。

相关文章:

C- 使用原子变量实现信号量

信号量 信号量&#xff08;Semaphore&#xff09;是并发编程中的一个核心同步原语&#xff0c;它在多进程和多线程环境下被设计用来协调不同的执行单元&#xff0c;确保它们在对共享资源的访问上达到同步和互斥。信号量内部维护一个计数器&#xff0c;该计数器的初始值可以被视…...

Pytorch与Onnx的转换与推理

Open Neural Network Exchange&#xff08;ONNX&#xff0c;开放神经网络交换&#xff09;格式&#xff0c;是一个用于表示深度学习模型的标准&#xff0c;可使模型在不同框架之间进行转移。 一、pytorch模型保存/加载 有两种方式可用于保存/加载pytorch模型 1&#xff09;文件…...

Linux权限详解

文章目录 1. shell命令及运行原理2. Linux权限的概念&#xff08;1&#xff09;用户种类&#xff08;2&#xff09;切换用户&#xff08;3&#xff09;命令提权 3. Linux权限管理&#xff08;1&#xff09;文件访问者的分类&#xff08;人&#xff09;&#xff08;2&#xff09…...

基于react18+arco+zustand通用后台管理系统React18Admin

React-Arco-Admin轻量级后台管理系统解决方案 基于vite4构建react18后台项目ReactAdmin。使用了reactarco-designzustandbizcharts等技术架构非凡后台管理框架。支持 dark/light主题、i18n国际化、动态路由鉴权、3种经典布局、tabs路由标签 等功能。 技术框架 编辑器&#xff…...

BAT031:按列表名单将路径a下的文件夹批量剪切到路径b

引言&#xff1a;编写批处理程序&#xff0c;实现按列表名单将路径a下的文件夹批量剪切到路径b。 一、新建Windows批处理文件 参考博客&#xff1a; CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132137544 二、写入批处理代码 1.右键新建的批处理文件&#xff0c;点击…...

随机专享记录第一话 -- RustDesk的自我搭建和使用

1.介绍 RustDesk是继TeamView、向日葵等远程桌面软件后的新起之秀,最主要的是开源的可自己搭建中继服务。相比于公共服务器,连接一次等待的时间要多久,用过TeamView的都知道,而且还是免费的,不像某些远程搞各种个人证书,各种登录设备限制! 先看看软件图,这是待连接界…...

【数据库】拼接字段 使用别名

拼接字段 使用别名 e . g . e.g. e.g. Vendors 表包含供应商名和电话信息&#xff0c;name 和 mobile&#xff1b;需要输出这两个属性的值的组合作为供应商的基本信息组合。 SELECT concat(name, _, mobile) FROM Vendors; -- 语句通过 MySQL 环境下测试&#xff0c;其他 DBMS…...

Golang设计22种模式

什么是设计模式 设计模式是面向对象软件的设计经验,是通常设计问题的解决方案。每一种设计模式系统的命名、解释和评价了面向对象中一个重要的和重复出现的设计。 设计模式的分类 创建模式 - 用来帮助我们创建对象的 工厂模式 (Factory Pattern)抽象工厂模式 (Abstract F…...

MMKV(3)

使用时遇到的问题 在项目的构建配置文件&#xff08;如 Gradle 或 Maven&#xff09;中添加相应的依赖项。 MMKV 是一个键值存储库&#xff0c;它存储的是原始的字节数组数据。需要存储和检索复杂的对象或数据结构&#xff0c;需要自行进行序列化和反序列化操作。可以使用任何…...

vivado报错警告之[Vivado 12-1017] Problems encountered:

文章目录 方法一方法二方法三&#xff08;作者最终解决&#xff09; 我们对vivado 的程序进行综合(Run Synthesis)时&#xff0c;可能会出现[Vivado 12-1017] Problems encountered: 1. Failed to delete one or more files in run directory的一个警告信息&#xff0c;导致我们…...

基于springboot汽车租赁系统

功能如下图所示 摘要 Spring Boot汽车租赁系统的设计旨在满足不断增长的租车市场需求&#xff0c;并通过简化开发和部署流程来提供方便的租车解决方案。系统采用了现代化的架构&#xff0c;主要基于以下技术栈&#xff1a; Spring Boot&#xff1a;作为后端的核心框架&#xff…...

C++禁用赋值操作符

1.禁用赋值操作符 在C中&#xff0c;void operator(const ClassName&) delete; 是一种特殊的语法&#xff0c;用于明确地禁止赋值操作符&#xff08;assignment operator&#xff09;的默认实现或自定义实现。 这通常用于防止类的实例被意外赋值。通过明确地删除赋值操作…...

小程序的数据驱动和vue的双向绑定有何异同?

小程序的数据驱动和Vue的双向绑定有以下异同之处&#xff1a; 异同点&#xff1a; 数据驱动&#xff1a;小程序的数据驱动是指通过编写数据绑定的代码&#xff0c;将数据与视图进行关联&#xff0c;当数据发生变化时&#xff0c;视图会自动更新。而Vue的双向绑定则是一种特殊的…...

Nvm管理NodeJs版本

文章目录 Nvm管理NodeJs版本一、前言1.简介2.环境 二、正文1.卸载NodeJs2.安装Nvm3.配置国内镜像4.Nvm使用5.其它1&#xff09;报错12&#xff09;报错2 Nvm管理NodeJs版本 一、前言 1.简介 Node Version Manager&#xff08;nvm&#xff09;可通过命令行快速安装和使用不同…...

阿里云国际站服务器开放端口详解!!

在互联网技术发展的今天&#xff0c;服务器扮演着至关重要的角色。作为云服务供给商&#xff0c;阿里云服务器供给了安稳、高效的服务&#xff0c;而敞开端口则是阿里云服务器功能的重要体现。本文将详细解读阿里云服务器敞开端口的意义、实现办法以及其带来的优点。 一、阿里云…...

【自动化测试入门】用Airtest - Selenium对Firefox进行自动化测试(0基础也能学会)

1. 前言 本文将详细介绍如何使用AirtestIDE驱动Firefox测试&#xff0c;以及脱离AirtestIDE怎么驱动Firefox&#xff08;VScode为例&#xff09;。看完本文零基础小白也能学会Firefox浏览器自动化测试&#xff01;&#xff01;&#xff01; 2. 如何使用AirtestIDE驱动Firefox…...

Python 爬虫入门:常见工具介绍

接着我的上一篇文章《网页爬虫完全指南》&#xff0c;这篇文章将涵盖几乎所有的 Python 网页爬取工具。我们从最基本的开始讲起&#xff0c;逐步涉及到当前最前沿的技术&#xff0c;并且对它们的利弊进行分析。 当然&#xff0c;我们不能全面地介绍每个工具&#xff0c;但这篇…...

uniGUI文件操作

一.文件上传TUniFileUploadButton TUniFileUploadButton主要属性&#xff1a; Filter: 文件类型过滤&#xff0c;有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸&#xff1b; Message&#xff1a;标题以及消息文本&#xff0c;可翻译成中文…...

Python多进程之分享(multiprocessing包)

threading和multiprocessing (可以阅读Python多线程与同步) multiprocessing包是Python中的多进程管理包。与threading.Thread类似&#xff0c;它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的…...

【试题028】C语言关于逻辑与的短路例题

1.题目&#xff1a;设inta1,b;&#xff0c;执行b0&&(a);后&#xff0c;变量a的值是&#xff1f; 2.代码解析&#xff1a; #include <stdio.h> int main() {//设inta1,b;执行b0&&(a);后&#xff0c;变量a的值是?int a 1, b;printf("表达式的值是…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...