C++ WonderTrader源码分析之自旋锁实现

一、介绍

在WonderTrader的文件SpinMutex.hpp定义了跨平台的自旋锁的实现。

二、实现原理

1、类 SpinMutex:自旋锁实现

SpinMutex 是一个轻量级的自旋锁(Spinlock)实现,用于多线程之间保护临界区资源。自旋锁通过不断尝试获取锁而不让出 CPU 控制权,在临界区非常短的场景下比 std::mutex 更高效

类定义与成员变量
class SpinMutex
{
private:std::atomic<bool> flag = { false };

含义:

  • flag 是一个原子布尔变量,标志锁的状态:
    • false:锁未被占用。
    • true:锁已被占用。
  • 使用 std::atomic 保证该变量在线程之间的读写是原子的,不会产生数据竞争。
lock() 方法:尝试加锁(进入临界区)
void lock()
{for (;;){if (!flag.exchange(true, std::memory_order_acquire))break;while (flag.load(std::memory_order_relaxed)){
#ifdef _MSC_VER_mm_pause();
#else__builtin_ia32_pause();
#endif}}
}

(1)、尝试抢锁

if (!flag.exchange(true, std::memory_order_acquire))break;

含义:

  • 尝试将 flag 从 false 变成 true。
  • exchange 是一个原子操作,返回交换前的值。
  • 如果原值是 false,说明锁空闲,抢锁成功,跳出循环。
  • memory_order_acquire 的作用:
    • 表示获取操作:确保当前线程在获取锁之后,看到的所有共享内存变动是“可见的”。
    • 保证锁之后的内存操作不会重排到 exchange 之前。

(2)、锁被占用,进入自旋等待

while (flag.load(std::memory_order_relaxed))
{
#ifdef _MSC_VER_mm_pause();
#else__builtin_ia32_pause();
#endif
}

含义:

  • 如果抢锁失败,说明 flag == true,就会进入这个 while,不断检测锁是否释放。
  • 自旋期间只读取,不尝试修改。
  • memory_order_relaxed:
    • 只要求原子性,不需要内存可见性或顺序一致性。
    • 适合用于自旋中不断读状态,无需同步其他内存操作。
  • _mm_pause() / __builtin_ia32_pause():
    • 都是CPU pause 指令,告诉处理器“我在忙等,不要发热也 不要让乱序执行干扰这个循环”。
    • 优化超线程(HT)下的性能,降低能耗和缓存一致性压力。
    • _mm_pause() 是 Intel/微软的,__builtin_ia32_pause() 是 GCC/Clang 提供的

这段代码的整体思路:

1 尝试交换(CAS):把 flag 从 false 设置为 true。
2 成功 → 抢到锁,退出。
3 失败 → 等着别人释放(即 flag 变为 false)。
4 不断读(load)+ pause,直到别人释放锁,继续尝试抢锁。

unlock() 方法:释放锁
void unlock()
{flag.store(false, std::memory_order_release);
}

含义:

  • 将 flag 设为 false,表示锁释放,别人可以抢锁了。
  • memory_order_release:
    • 表示释放操作:保证当前线程在释放锁前对共享内存的所有写操作,对下一个加锁的线程是可见的。
    • 保证写操作不会重排序到 store 之后。
整体流程
Thread A                      Thread B
---------                    ----------
flag == falseexchange(true) → 成功       
flag = true(锁住)          
执行临界区                   
↓                             
store(false)(解锁)           load(flag)falseexchange(true) → 成功进入临界区
2、类 SpinLock:RAII 自旋锁管理器
构造函数:
SpinLock(SpinMutex& mtx) :_mutex(mtx) { _mutex.lock(); }

接收一个 SpinMutex 引用,并立即加锁。

析构函数:
~SpinLock() { _mutex.unlock(); }

离开作用域时自动释放锁,避免忘记 unlock() 导致死锁。

拷贝构造 & 赋值删除:
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;

禁止复制和赋值,避免一个锁对象被多次释放,保证线程安全。

三、使用举例

#include "SpinMutex.hpp"
#include <vector>
#include <thread>SpinMutex spin_mtx;
int counter = 0;
void worker(int id, int loops)
{for (int i = 0; i < loops; ++i){SpinLock lock(spin_mtx); // 自动加锁++counter;               // 临界区// 离开作用域时自动解锁}
}
int main() {int thread_count = 4;int loops = 100000;std::vector<std::thread> threads;threads.reserve(thread_count);for (int i = 0; i < thread_count; ++i)threads.emplace_back(worker, i, loops);for (auto& t : threads)t.join();std::cout << "Final counter = " << counter << std::endl;
}

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

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

相关文章

【AI大模型】Spring AI 基于Redis实现对话持久存储详解

目录 一、前言 二、Spring AI 会话记忆介绍 2.1 Spring AI 会话记忆概述 2.2 常用的会话记忆实现方式 2.2.1 集成数据库持久存储会话实现步骤 2.3 适用场景 三、Spring AI基于内存会话记忆存储 3.1 本地开发环境准备 3.2 工程搭建与集成 3.2.1 添加核心依赖 3.3.2 添…

Numpy科学计算与数据分析:Numpy数据分析与图像处理入门

Numpy实战&#xff1a;从数据分析到图像处理 学习目标 通过本课程&#xff0c;学员将学会运用Numpy库进行数据分析和图像处理。学习如何使用Numpy进行数据的高效处理&#xff0c;以及如何利用Numpy进行基本的图像操作。 相关知识点 Numpy的数据分析和图像处理 学习内容 1…

Vue框架总结案例

目录 一、验证用户名是否已经被注册过 二、过滤器 三、图书管理系统 四、axios网络请求 一、验证用户名是否已经被注册过 1.案例 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><script src"j…

hyper-v虚拟机启动失败:Virtual Pci Express Port无法打开电源,因为发生错误,找不到即插即用设备

启动错误 今天启动某个hyper-v虚拟机时&#xff0c;启动失败了&#xff0c;大概的错误信息为&#xff1a;尝试更改“ubuntu_desktop_2204”的状态时应用程序遇到错误。Virtual Pci Express Port (实例 ID 0445948B-C377-4912-AEEB-58A3D45C5694): 无法开机&#xff0c;因…

CSS包含块与百分比取值机制完全指南

引言&#xff1a;为什么需要理解包含块&#xff1f; 在CSS布局的世界中&#xff0c;包含块(Containing Block) 是一个基础但至关重要的概念。它就像是一个隐形的参考框架&#xff0c;决定了元素如何定位、尺寸如何计算以及百分比值如何解析。许多CSS开发者在使用百分比单位时遇…

Numpy科学计算与数据分析:Numpy数组操作入门:合并、分割与重塑

Numpy数组操作实战 学习目标 通过本课程的学习&#xff0c;学员将掌握Numpy中数组的基本操作&#xff0c;包括数组的合并、分割以及重塑等技巧&#xff0c;能够灵活运用这些操作处理数据&#xff0c;为后续的科学计算和数据分析打下坚实的基础。 相关知识点 Numpy数组操作 …

11_Mybatis 是如何进行DO类和数据库字段的映射的?

11_Mybatis 是如何进行DO类和数据库字段的映射的&#xff1f; 假设 VideoAbnormalContentMapper.xml 文件有如下方法&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN&quo…

2025年渗透测试面试题总结-06(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 逻辑漏洞 一、三大高危业务逻辑漏洞及修复方案 1. 订单金额篡改&#xff08;参数操纵&#xff09; 2. 重…

SpringBoot激活指定profile的方式

题目详细答案在 Spring Boot 中&#xff0c;可以通过多种方式激活指定的 Profile&#xff0c;以便在不同的环境中使用不同的配置。在application.properties文件中激活可以在默认的application.properties文件中通过spring.profiles.active属性激活某个 Profile。# application…

Pytest项目_day10(接口的参数传递)

接口的参数传递 如果我们需要在一个测试用例中使用另一个测试用例中获得的数据&#xff0c;应该怎么办&#xff1f; 解决方案一&#xff1a;使用函数返回值 - 我们可以在另一个测试用例中使用return来返回所需的数据&#xff0c;并在其他的测试用例中调用该测试用例&#xff08…

深信服GO面试题及参考答案(上)

Go 和 Java 的特点和区别是什么? Go 和 Java 都是静态类型、编译型语言,但在设计理念、语法特性、并发模型等方面存在显著差异,具体如下: 从语言设计目标来看,Go 由 Google 开发,旨在解决大型系统开发中的复杂性,强调“简单、高效、并发”,语法简洁,摒弃了许多传统面向…

BGP笔记及综合实验

BGP基础一、BGP产生背景 - BGP定义&#xff1a;边界网关协议&#xff08;BGP&#xff09;是自治系统间的动态路由协议&#xff0c;属于外部网关协议&#xff08;EGP&#xff09;。 - 自治系统&#xff08;AS&#xff09;&#xff1a;由统一管理、运行同一IGP协议的路由器组成&a…

全栈:如何判断自己应该下载哪个版本的Tomcat

版本兼容性矩阵 https://tomcat.apache.org/whichversion.html https://tomcat.apache.org/download-11.cgi 介绍一下这些版本的不同点&#xff1a; 一、按系统选&#xff08;优先看这个&#xff09; 1.Windows 系统&#xff08;普通使用&#xff0c;非服务自启&#xff09…

Redis的Linux安装

可以直接命令下载 wget http://download.redis.io/releases/redis-5.0.4.tar.gz下载好之后解压缩&#xff0c;并且重命名为redis 由于redis是c语言编写的&#xff0c;所以我们需要先安装gcc&#xff0c;安装的命令如下&#xff1a;yum -y install gcc 安装成功后输入 : gcc -v…

14-netty基础-手写rpc-提供方(服务端)-06

netty系列文章&#xff1a; 01-netty基础-socket02-netty基础-java四种IO模型03-netty基础-多路复用select、poll、epoll04-netty基础-Reactor三种模型05-netty基础-ByteBuf数据结构06-netty基础-编码解码07-netty基础-自定义编解码器08-netty基础-自定义序列化和反序列化09-n…

连续时间和数字之间频率的偏差以及相位补偿

接下来需要讲解在连续时间域下的角频率以及在离散化后的数字角频率。上面可以知道模拟角频率和数字的区别 接下来介绍相位 相位单位是弧度无频偏&#xff1a; 对于数字来说是对连续信号采样后的结果&#xff0c;数字的角频率 &#xff0c;就是相位的递增量&#xff0c;表示每个…

《Git从入门到精通:告别版本管理混乱》

坚持用 清晰易懂的图解 代码语言&#xff0c;让每个知识点变得简单&#xff01; &#x1f680;呆头个人主页详情 &#x1f331; 呆头个人Gitee代码仓库 &#x1f4cc; 呆头详细专栏系列 座右铭&#xff1a; “不患无位&#xff0c;患所以立。” 《Git从入门到精通&#xff1a…

小红书开源多模态视觉语言模型DOTS-VLM1

项目简介与模型基本介绍 DOTS-VLM1 是由小红书希实验室(Rednote HiLab)开源的多模态视觉语言模型(Vision-Language Model, VLM),旨在推动视觉与语言理解的融合研究。DOTS-VLM1 采用主流的编码-融合-解码架构,支持图片与文本的联合理解与生成,适用于图文问答、图片描述、…

【Git】企业级使用

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 基本概念 Git 有三个核心区域&#xff0c;分别是工作区、暂存区和版本库&#xff0c;理解这三个区域是掌握 Git 的基础。​ ​ 工作区就是我们电脑里能看到的文件目录&…

Druid学习笔记 02、快速使用Druid的SqlParser解析

文章目录前言本章节源码描述认识作者官方文档快速入门demo案例引入依赖获取到SQL的AST(抽象语法树)使用visitor完成表、字段、表达式解析汇总总结一、简介1.1、和Antlr生成Parser的区别1.2、Druid SQL Parser的使用场景二、各种语法支持三、性能四、Druid SQL Parser的代码结构…