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

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.xdnf.cn/news/17282.html

相关文章:

  • 宁商平台税务新举措:合规护航,服务暖心
  • 视频质量检测中准确率↑32%:陌讯多模态评估方案实战解析
  • Web Worker 性能革命:让浏览器多线程为您的应用加速
  • 使用 Gulp 替换 XML 文件内容
  • 解决MinIO上传图片后返回URL无法访问的问题
  • 从深度伪造到深度信任:AI安全的三场攻防战
  • web端-登录页面验证码的实现(springboot+vue前后端分离)超详细
  • 5- Python 网络爬虫 — 如何突破 JS 动态渲染壁垒?工具原理与实战全解析
  • K8s 常见故障案例分析
  • KLA/TENCOR ALTAIR 8900
  • vscode 配置
  • 灵活、高效,Sub-GHz频段中的轻量化组网方案
  • linux-文件系统
  • Android 中 实现自定义 Dialog 提示框
  • 32-Hive SQL DML语法之查询数据
  • 无人机仿真环境搭建
  • 软件包管理、缓存、自定义 YUM 源
  • 基于Vue.js和Golang构建高效在线客服系统:前端实现与后端交互详解
  • Linux网络--1、网络基础
  • 分布式系统性能优化实战:从瓶颈定位到架构升级
  • [GESP2023012 五级] 2023年12月GESP C++五级上机题题解,附带讲解视频!
  • c++初学day1(类比C语言进行举例,具体原理等到学到更深层的东西再进行解析)
  • WiFi 核心概念与实战用例全解
  • 17.14 CogVLM-17B多模态模型爆肝部署:4-bit量化+1120px高清输入,A100实战避坑指南
  • SimpleMindMap:一个强大的Web思维导图
  • CVRF 是什么?微软弃用 MS 编号后,网络安全的下一个标准
  • 【面经】2025年软件测试面试题,精选100 道(附答案)
  • 为什么通过CreateThread创建的线程调用C/C++运行库函数不稳定
  • 交换机100G模块远距离连接踩坑记录
  • Vibe coding现在能用于生产吗?