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

C- 使用原子变量实现自旋锁

自旋锁

自旋锁(Spinlock)是一种常用于多线程编程中的低开销锁,其特点是当线程尝试获取锁而锁已被其他线程占用时,该线程会处于一个持续的忙等待(busy-wait)状态,直到它可以获取到锁为止。这种方法避免了线程切换和上下文切换的开销,但是如果锁被持有的时间较长,它可能会造成CPU时间的浪费。

自旋锁最适用于以下经典场景:

  1. 短临界区:当需要保护的代码执行非常快,锁的持有时间非常短时,自旋锁是非常有效的。

  2. 低竞争:当很少有线程试图同一时间获取锁时,自旋锁是有用的。

  3. 实时系统:在某些实时系统中,线程切换和上下文切换的代价可能非常高,自旋锁可能是一个更好的选择,因为它们可以确保线程在短时间内完成其工作。

  4. 无法睡眠的环境:在某些环境中,如内核中断处理程序或其他不允许睡眠的环境中,使用自旋锁可能是唯一的同步选项。

  5. 多核和多处理器系统:在多核和多处理器的系统中,当一个线程在一个核上忙等待,另一个线程可能在另一个核上释放锁,这种情况下,自旋锁可能比其他类型的锁更高效。

然而,值得注意的是,如果锁可能被持有很长时间或有高竞争的情况,自旋锁可能不是一个好的选择,因为它可能导致大量的CPU时间浪费。在这种情况下,其他的锁机制,如互斥锁或读写锁,可能是更好的选择。

实现自旋锁

使用原子变量实现自旋锁涉及到利用原子操作来确保锁的原子性。以下是使用C11中的stdatomic.h来实现一个简单的自旋锁:

#include <stdio.h>
#include <stdatomic.h>
#include <pthread.h>typedef struct {atomic_flag flag;
} spinlock_t;void spinlock_init(spinlock_t *lock) {atomic_flag_clear(&lock->flag);
}void spinlock_lock(spinlock_t *lock) {while (atomic_flag_test_and_set(&lock->flag));
}void spinlock_unlock(spinlock_t *lock) {atomic_flag_clear(&lock->flag);
}spinlock_t lock;
int shared_data = 0;void *worker(void *arg) {for (int i = 0; i < 100000; ++ i) {spinlock_lock(&lock);shared_data ++;spinlock_unlock(&lock);}pthread_exit(0);
}int main() {pthread_t t1, t2;spinlock_init(&lock);pthread_create(&t1, NULL, worker, NULL);pthread_create(&t2, NULL, worker, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("Shared data: %d\n", shared_data);pthread_exit(0);
}

这里的关键是atomic_flag_test_and_set函数,它检查atomic_flag的当前值,如果它是false(即锁未被持有),则设置它为true(锁被持有)并返回原始值。这个操作是原子的,意味着在多线程环境中,只有一个线程能够成功地将flag设置为true。其他尝试获取锁的线程将会在while循环中自旋,直到锁被释放。

在 C11 标准中,atomic_flag的默认/初始状态是未设置(即其值为false)。当使用atomic_flag_clear()函数时,会将其设置回这个未设置状态。

但要注意,当使用atomic_flag变量时,为了确保其正确初始化,应该使用宏ATOMIC_FLAG_INIT。例如:

spinlock_t mylock = { ATOMIC_FLAG_INIT };

在上述自旋锁示例中,我们使用了atomic_flag_clear()函数来确保在初始化后标志是清除的(即设置为false)。


补充

atomic_flag

atomic_flag是C11标准中定义的一种原子类型,用于实现原子标记。它是原子操作库中最基础的组件,并且是确保原子性的最简单工具。原子类型的目的是在多线程环境中提供对单个数据的无锁访问,以确保数据操作的原子性。

以下是关于atomic_flag的一些关键点:

  1. 简单性atomic_flag只有两个可能的状态:设置(true)和未设置(false)。

  2. 原子性:操作atomic_flag的函数都是原子的,这意味着在多线程环境中对其进行的操作都是不可分割的。当一个线程在操作它时,其他线程无法干扰这个操作。

  3. 操作

    • atomic_flag_test_and_set:这个函数检查atomic_flag的当前状态。如果它未被设置,函数会设置它并返回先前的值。这个函数通常用于尝试获取锁。
    • atomic_flag_clear:这个函数将atomic_flag重置为未设置状态。这个函数通常用于释放锁。
  4. 初始化:要正确初始化atomic_flag,应使用ATOMIC_FLAG_INIT宏。

  5. 用途:由于其简单性,atomic_flag通常用于构建更复杂的同步原语,如自旋锁。

  6. 无锁保证atomic_flag提供了锁自由的保证。这意味着在其操作中不存在可能导致线程阻塞的锁。这是利用硬件提供的原子操作来实现的。

总的来说,atomic_flag是一个低级的同步原语,通常用于构建高级的同步工具或数据结构。尽管它看起来简单,但其提供的原子性保证使其在并发编程中非常有价值。

atomic_flag_clear()

atomic_flag_clear() 是 C11 和 C++11(及更高版本)中的原子操作库的一部分,专门用于操作 atomic_flag 类型。它的主要作用是将 atomic_flag 对象的状态重置为“清除”状态。

以下是关于 atomic_flag_clear() 的详细介绍:

  1. 函数签名:

    void atomic_flag_clear(volatile atomic_flag *obj);
    void atomic_flag_clear(atomic_flag *obj);
    
  2. 参数:

    • obj: 指向要清除的 atomic_flag 对象的指针。
  3. 返回值:

    • 这个函数没有返回值。
  4. 功能:

    • atomic_flag_clear() 函数将给定的 atomic_flag 对象的状态设置为清除状态(也就是 false 或未设置状态)。
  5. 原子性:

    • atomic_flag_clear() 函数的操作是原子的,这意味着它是不可分割的。当一个线程调用此函数来清除标记时,其他线程无法看到这个操作的任何中间状态。这确保了对该标记的所有操作都是线程安全的。
  6. 常见用途:

    • 通常,在使用 atomic_flag 作为自旋锁的基础时,当线程释放锁时,它会调用 atomic_flag_clear() 来标记锁为可用。
  7. 注意事项:

    • 在调用 atomic_flag_clear() 之前,通常会有一些其他的原子检查或操作来确定标记是否已经被设置,以确保正确的并发行为。

总之,atomic_flag_clear() 是一个基础的原子操作,它为更复杂的并发控制结构(如自旋锁)提供了基本的线程安全释放机制。

atomic_flag_test_and_set()

atomic_flag_test_and_set() 是 C11 和 C++11 标准(及更高版本)中的原子操作库的一部分,主要用于 atomic_flag 类型。这个函数的主要功能是测试 atomic_flag 的当前状态,并将其设置为 true。这一操作是原子的,确保在多线程环境下其行为是一致的和预期的。

以下是关于 atomic_flag_test_and_set() 的详细介绍:

  1. 函数签名:

    bool atomic_flag_test_and_set(volatile atomic_flag *obj);
    bool atomic_flag_test_and_set(atomic_flag *obj);
    

    在 C++ 中,还有一个额外的重载版本,支持 memory_order 参数,允许指定该操作的内存序语义。

  2. 参数:

    • obj: 指向要测试和设置的 atomic_flag 对象的指针。
  3. 返回值:

    • 如果 atomic_flag 之前的状态是已设置(true),则返回 true;否则返回 false
  4. 功能:

    • atomic_flag_test_and_set() 函数首先检查给定的 atomic_flag 对象的状态。
    • 如果其状态为未设置(false),则将其设置为 true 并返回 false
    • 如果其状态已经是设置的(true),则保持其状态并返回 true
  5. 原子性:

    • atomic_flag_test_and_set() 函数的操作是原子的。这意味着当一个线程正在执行此函数时,其他线程无法干扰或看到这个操作的任何中间状态。这是并发编程中非常关键的特性,尤其是在实现如自旋锁这样的并发控制结构时。
  6. 常见用途:

    • atomic_flag_test_and_set() 常被用作基于 atomic_flag 的自旋锁的核心。如果一个线程尝试获取锁(通过调用 atomic_flag_test_and_set())并且返回 false,这意味着该线程成功获取了锁。如果返回 true,则锁已经被其他线程持有,因此该线程必须等待或尝试其他操作。
  7. 注意事项:

    • 当使用 atomic_flag_test_and_set() 函数时,应该始终确保对应的 atomic_flag 在使用前已经被清除(使用 atomic_flag_clear())。

总之,atomic_flag_test_and_set() 提供了一种在多线程环境中原子地测试和设置标志的方法,它是许多并发控制结构的基础。

相关文章:

C- 使用原子变量实现自旋锁

自旋锁 自旋锁&#xff08;Spinlock&#xff09;是一种常用于多线程编程中的低开销锁&#xff0c;其特点是当线程尝试获取锁而锁已被其他线程占用时&#xff0c;该线程会处于一个持续的忙等待&#xff08;busy-wait&#xff09;状态&#xff0c;直到它可以获取到锁为止。这种方…...

汇编的指令

减法类指令&#xff1a; 不带借位的减法&#xff1a; sub dest,src;dest(dest)-(src) 注意&#xff1a; 1、源操作数和目的操作数不能同时为段寄存器或存储单元 2、对标志位有影响&#xff0c;主要影响CF、ZF、OF、SF。 带借位的减法&#xff1a; sbb dest,src;dest(dest)-(…...

《数据结构、算法与应用C++语言描述》使用C++语言实现数组队列

《数据结构、算法与应用C语言描述》使用C语言实现数组队列 定义 队列的定义 队列&#xff08;queue&#xff09;是一个线性表&#xff0c;其插入和删除操作分别在表的不同端进行。插入元素的那一端称为队尾&#xff08;back或rear&#xff09;&#xff0c;删除元素的那一端称…...

零基础如何学习自动化测试

现在很多测试人员有些急于求成&#xff0c;没有任何基础想当然的&#xff0c;要在一周内上手自动化测试。 在自动化的过程中时候总有人会犯很低级的问题&#xff0c;有语法问题&#xff0c;有定位问题&#xff0c;而且有人居然连__init__.py 文件名都弄错误&#xff0c;还有将…...

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

1.信息化战略与实施 2.UML图&#xff08;12个&#xff09; 3.结构化设计&#xff08;耦合&#xff09; 4.SMP与AMP的区别&#xff08;多核处理器的工作方式&#xff09; 多核处理器一般有SMP和AMP两种不同的工作方式: SMP(对称多处理技术)&#xff1a;将2颗完全一样的处理器封…...

【MySQL系列】- Select查询SQL执行过程详解

【MySQL系列】- Select查询SQL执行过程详解 文章目录 【MySQL系列】- Select查询SQL执行过程详解一、SQL查询语句的执行过程二、SQL执行过程详解2.1. 连接器2.2. 查询缓存2.3. 分析器2.4. 优化器2.5. 执行器 三、undo log 和 redo log作⽤3.1. redo log &#xff08;重做日志&a…...

软考高级信息系统项目管理师系列之:信息系统项目管理师论文评分参考标准

软考高级信息系统项目管理师系列之:信息系统项目管理师论文评分参考标准 论文满分是 75 分,论文评分可分为优良、及格与不及格 3 个档次。评分的分数可分为: 60 分至 75 分优良(相当于百分制 80 分至 100 分)。45 分至 59 分及格(相当于百分制 60 分至 79 分)。0 分至 44 分…...

MyBatis--多案例让你熟练使用CRUD操作

目录 一、前期准备 二、两种实现CRUD方式 三、增加数据&#xff08;INSERT&#xff09; 四、删除数据&#xff08;DELETE&#xff09; 五、查询数据&#xff08;SELECT&#xff09; 六、更新数据&#xff08;UPDATE&#xff09; 一、前期准备 1.创建maven项目并在pom文件…...

用Python造轮子

目录 背景安装setuptools库准备要打包的代码创建setup.py文件打包生成whl文件把库装到电脑上使用这个库 背景 如何把自己写的代码&#xff0c;打包成库方便其他人使用 安装setuptools库 正所谓想要富先修路&#xff0c;先把造轮子要用的库装上 pip install wheel pip insta…...

ARM 堆栈寻址类型区分

文章目录 堆栈指向分类堆栈指向数据分类满递增与满递减空递增与空递减 堆栈指向分类 根据堆栈指针的指向的方向不同&#xff0c;可以划分为向上生成型和向下生成型。 向上生成型&#xff1a; 随着数据的入栈&#xff0c;堆栈的指针逐渐增大&#xff0c;称为&#xff1a;递增…...

每日一练 | 网络工程师软考真题Day43

1、在生成树协议〔STP〕IEEE 802.1d中&#xff0c;根据 来选择根交换机。 A&#xff0e;最小的MAC地址 B&#xff0e;最大的MAC地址 C&#xff0e;最小的交换机ID D&#xff0e;最大的交换机ID 2、在快速以太网物理层标准中&#xff0c;使用两对5类无屏蔽双绞线的是 。 A&…...

jsonXML格式化核心代码

json格式化&#xff1a; 依赖&#xff1a; <dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>2.6.0</version><scope>compile</scope> </dependency> string t…...

PTQ量化和QAT量化

目录 1--PTQ量化 2--QAT量化 1--PTQ量化 PTQ量化表示训练后量化&#xff08;Post Training Quantization&#xff09;。使用一批校准数据对训练好的模型进行校准&#xff0c;将训练好的FP32网络直接转换为定点计算的网络&#xff0c;过程中无需对原始模型进行任何训练&#x…...

【Django 02】数据表构建、数据迁移与管理

1. Django 构建数据表创建与数据迁移 1.1 数据表创建 1.1.1 模块功能 如前所述&#xff0c;models.py文件主要用一个 Python 类来描述数据表。运用这个类,可以通过简单的 Python 代码来创建、检索、更新、删除 数据库中的记录而无需写一条又一条的SQL语句。今天的例子就是在…...

一天吃透Java集合面试八股文

内容摘自我的学习网站&#xff1a;topjavaer.cn 常见的集合有哪些&#xff1f; Java集合类主要由两个接口Collection和Map派生出来的&#xff0c;Collection有三个子接口&#xff1a;List、Set、Queue。 Java集合框架图如下&#xff1a; List代表了有序可重复集合&#xff0c…...

高级深入--day36

Settings Scrapy设置(settings)提供了定制Scrapy组件的方法。可以控制包括核心(core),插件(extension),pipeline及spider组件。比如 设置Json Pipeliine、LOG_LEVEL等。 参考文档:Settings — Scrapy 1.0.5 文档 内置设置参考手册 BOT_NAME 默认: scrapybot 当您使用 sta…...

Jmeter接口测试工具的一些使用小技巧

如何使用英文界面的JMeter Jmeter启动时会自动判断操作系统的locale 并选择合适的语言启动&#xff0c;所以&#xff0c;我们启动jmeter后&#xff0c;其会出现一个倍感亲切的中文界面。但由于jmeter本身的汉化工作做得不好&#xff0c;你会看到有未被汉化的选项及元件的参数。…...

黄金眼PAAS化数据服务DIFF测试工具的建设实践 | 京东云技术团队

一、背景介绍 黄金眼PAAS化数据服务是一系列实现相同指标服务协议的数据服务&#xff0c;各个服务间按照所生产指标的主题作划分&#xff0c;比如交易实时服务提供实时交易指标的查询&#xff0c;财务离线服务提供离线财务指标的查询。黄金眼PAAS化数据服务支撑了黄金眼APP、黄…...

深入了解RPA业务流程自动化的关键要素

在RPA业务流程自动化实施过程中&#xff0c;哪些因素起着至关重要的作用&#xff1f;这其实没有一个通用的答案&#xff0c;每一个RPA业务流程自动化的部署&#xff0c;都需要结合具体场景去调整&#xff0c;并且进行全面的规划。 首当其冲是要关注以下几点&#xff1a; 1、专…...

CSS记录

1.标准的CSS的盒子模型&#xff1f;与低版本IE的盒子模型有什么不同的&#xff1f; 标准盒子模型box-sizing: border-box; 宽度内容的宽度&#xff08;content&#xff09; border padding margin 低版本IE盒子模型&#xff1a;宽度内容宽度&#xff08;contentborderpaddin…...

北外滩餐饮新店突围战:揭秘AI大模型如何让搜索流量“精准上门”

如果你是北外滩一位新开业的餐厅老板&#xff0c;是否正面临这样的困境&#xff1a;店铺装修精美、菜品独具匠心&#xff0c;但门口罗雀&#xff0c;预期的客流迟迟不来&#xff1f;你试过在平台买推广、请达人探店&#xff0c;效果却如昙花一现&#xff0c;成本居高不下&#…...

Python数据清洗实战:缺失数据与异常值处理全攻略

在数据分析和机器学习的工作流中&#xff0c;数据清洗是绕不开的关键环节。粗糙的数据就像未打磨的原石&#xff0c;即便算法再精妙&#xff0c;也难以提炼出有价值的信息。其中&#xff0c;缺失数据与异常值是最常见的两类问题&#xff0c;它们不仅会干扰统计分析结果&#xf…...

终极指南:10个技巧快速解决iOS符号拦截失败问题

终极指南&#xff1a;10个技巧快速解决iOS符号拦截失败问题 【免费下载链接】fishhook A library that enables dynamically rebinding symbols in Mach-O binaries running on iOS. 项目地址: https://gitcode.com/gh_mirrors/fi/fishhook 如果你在使用fishhook进行iOS…...

终极指南:如何自定义Android RecyclerView ItemAnimator动画扩展

终极指南&#xff1a;如何自定义Android RecyclerView ItemAnimator动画扩展 【免费下载链接】android-advancedrecyclerview RecyclerView extension library which provides advanced features. (ex. Googles Inbox app like swiping, Play Music app like drag and drop sor…...

Agent在财务场景有哪些核心应用?深度解析2026企业智能化转型路径

站在2026年的技术节点回望&#xff0c;财务部门早已从传统的“记账中心”转型为企业的“战略决策大脑”。AI Agent&#xff08;人工智能助手/智能体&#xff09;的爆发式应用&#xff0c;彻底终结了繁琐的表单时代。与2024年的实验性尝试不同&#xff0c;当下的财务Agent具备了…...

新手福音:在快马平台体验vscode codex式辅助,轻松写出第一行代码

最近在学编程&#xff0c;发现很多新手&#xff08;包括我自己&#xff09;最头疼的就是面对空白的编辑器不知道从哪下手。传统的学习方式要么是直接看教程照抄代码&#xff0c;要么是硬啃文档记语法&#xff0c;很容易劝退。直到我发现了InsCode(快马)平台的智能辅助功能&…...

终极指南:如何用3分钟为Windows换上《蔚蓝档案》风格光标主题

终极指南&#xff1a;如何用3分钟为Windows换上《蔚蓝档案》风格光标主题 【免费下载链接】BlueArchive-Cursors Custom mouse cursor theme based on the school RPG Blue Archive. 项目地址: https://gitcode.com/gh_mirrors/bl/BlueArchive-Cursors 每天面对电脑工作…...

【2026年最新600套毕设项目分享】springboot智慧医疗管理系统(14315)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告/任务书&#xff09;远程调试控屏包运行一键启动项目&…...

每日一题 力扣 3418. 机器人可以获得的最大金币数 力扣 215. 数组中的第K个最大元素 动态规划 TopK问题 C++ 题解

文章目录力扣 3418. 机器人可以获得的最大金币数题目描述思路简介代码实现复杂度分析力扣 215. 数组中的第K个最大元素题目描述思路简介代码实现复杂度分析踩坑记录力扣 3418. 机器人可以获得的最大金币数 题目描述 力扣 3418. 机器人可以获得的最大金币数 示例 1&#xff1…...

AI 推理引擎的并行化实现

AI推理引擎的并行化实现&#xff1a;加速智能决策的关键 随着人工智能技术的快速发展&#xff0c;AI推理引擎已成为许多应用的核心组件&#xff0c;从自动驾驶到医疗诊断&#xff0c;再到智能客服&#xff0c;其高效性直接影响用户体验和系统性能。随着模型规模的扩大和实时性…...