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;
}
注意:
-
这个简单的信号量实现使用了"忙等待"或自旋,这可能会导致性能问题,尤其是在高度竞争的情况下。
-
atomic_compare_exchange_weak
函数尝试将sem->value
更新为expected - 1
,只有当sem->value
的当前值与expected
匹配时才会这样做。如果不匹配,函数将返回false
,并在expected
中设置当前的sem->value
。 -
在真实环境中,可能需要考虑使用更复杂的策略(例如,当信号量值为0时,线程进入休眠状态而不是持续自旋)。
-
虽然这个实现提供了原子操作的信号量,但它不是传统的信号量,因为它并不提供线程阻塞功能。这意味着当信号量的值为0时,线程将持续自旋,直到它可以获取信号量。
相关文章:
C- 使用原子变量实现信号量
信号量 信号量(Semaphore)是并发编程中的一个核心同步原语,它在多进程和多线程环境下被设计用来协调不同的执行单元,确保它们在对共享资源的访问上达到同步和互斥。信号量内部维护一个计数器,该计数器的初始值可以被视…...
Pytorch与Onnx的转换与推理
Open Neural Network Exchange(ONNX,开放神经网络交换)格式,是一个用于表示深度学习模型的标准,可使模型在不同框架之间进行转移。 一、pytorch模型保存/加载 有两种方式可用于保存/加载pytorch模型 1)文件…...

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

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

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

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

【数据库】拼接字段 使用别名
拼接字段 使用别名 e . g . e.g. e.g. Vendors 表包含供应商名和电话信息,name 和 mobile;需要输出这两个属性的值的组合作为供应商的基本信息组合。 SELECT concat(name, _, mobile) FROM Vendors; -- 语句通过 MySQL 环境下测试,其他 DBMS…...
Golang设计22种模式
什么是设计模式 设计模式是面向对象软件的设计经验,是通常设计问题的解决方案。每一种设计模式系统的命名、解释和评价了面向对象中一个重要的和重复出现的设计。 设计模式的分类 创建模式 - 用来帮助我们创建对象的 工厂模式 (Factory Pattern)抽象工厂模式 (Abstract F…...
MMKV(3)
使用时遇到的问题 在项目的构建配置文件(如 Gradle 或 Maven)中添加相应的依赖项。 MMKV 是一个键值存储库,它存储的是原始的字节数组数据。需要存储和检索复杂的对象或数据结构,需要自行进行序列化和反序列化操作。可以使用任何…...

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

基于springboot汽车租赁系统
功能如下图所示 摘要 Spring Boot汽车租赁系统的设计旨在满足不断增长的租车市场需求,并通过简化开发和部署流程来提供方便的租车解决方案。系统采用了现代化的架构,主要基于以下技术栈: Spring Boot:作为后端的核心框架ÿ…...
C++禁用赋值操作符
1.禁用赋值操作符 在C中,void operator(const ClassName&) delete; 是一种特殊的语法,用于明确地禁止赋值操作符(assignment operator)的默认实现或自定义实现。 这通常用于防止类的实例被意外赋值。通过明确地删除赋值操作…...
小程序的数据驱动和vue的双向绑定有何异同?
小程序的数据驱动和Vue的双向绑定有以下异同之处: 异同点: 数据驱动:小程序的数据驱动是指通过编写数据绑定的代码,将数据与视图进行关联,当数据发生变化时,视图会自动更新。而Vue的双向绑定则是一种特殊的…...

Nvm管理NodeJs版本
文章目录 Nvm管理NodeJs版本一、前言1.简介2.环境 二、正文1.卸载NodeJs2.安装Nvm3.配置国内镜像4.Nvm使用5.其它1)报错12)报错2 Nvm管理NodeJs版本 一、前言 1.简介 Node Version Manager(nvm)可通过命令行快速安装和使用不同…...
阿里云国际站服务器开放端口详解!!
在互联网技术发展的今天,服务器扮演着至关重要的角色。作为云服务供给商,阿里云服务器供给了安稳、高效的服务,而敞开端口则是阿里云服务器功能的重要体现。本文将详细解读阿里云服务器敞开端口的意义、实现办法以及其带来的优点。 一、阿里云…...

【自动化测试入门】用Airtest - Selenium对Firefox进行自动化测试(0基础也能学会)
1. 前言 本文将详细介绍如何使用AirtestIDE驱动Firefox测试,以及脱离AirtestIDE怎么驱动Firefox(VScode为例)。看完本文零基础小白也能学会Firefox浏览器自动化测试!!! 2. 如何使用AirtestIDE驱动Firefox…...

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

uniGUI文件操作
一.文件上传TUniFileUploadButton TUniFileUploadButton主要属性: Filter: 文件类型过滤,有图片image/* audio/* video/*三种过滤 MaxAllowedSize: 设置文件最大上传尺寸; Message:标题以及消息文本,可翻译成中文…...
Python多进程之分享(multiprocessing包)
threading和multiprocessing (可以阅读Python多线程与同步) multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的…...

【试题028】C语言关于逻辑与的短路例题
1.题目:设inta1,b;,执行b0&&(a);后,变量a的值是? 2.代码解析: #include <stdio.h> int main() {//设inta1,b;执行b0&&(a);后,变量a的值是?int a 1, b;printf("表达式的值是…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...