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

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.dtcms.com/a/321972.html

相关文章:

  • nflsoi 8.8 题解
  • CF每日3题(1400-1700)
  • 第9章 AI 安全、可解释性与伦理合规
  • 3天落地企业级应用,JNPF+AI重塑开发效率
  • sqli-labs靶场less46-less50
  • 传送带包裹漏检率↓78%!陌讯动态感知模型在物流分拣的实战优化
  • dMSA 滥用 (BadSuccessor) 导致权限升级:使用 ADAudit Plus 监控关键属性更改
  • Python使用LLM把自然语言翻译成SQL语句
  • 线程组和线程池的基本用法
  • 深入理解 SwiftUI 布局:VStack、HStack 和表单控件全解析
  • 电脑和手机访问网站,自动检测跳转不同网站
  • 将2小时的财报OCR识别录入缩短至5分钟,如何实现财报智能OCR录入
  • 创建一个Vue3项目
  • TLF35584芯片功能总结
  • Python基础语法练习
  • 力扣-56.合并区间
  • ESP32-menuconfig(4) -- Partition Table
  • [优选算法专题一双指针——三数之和]
  • Google再次颠覆自家模型,使用 MoR 模型打破 Transformer 模型壁垒
  • Java选手如何看待Golang
  • webapi项目添加访问IP限制
  • 根据字符出现频率排序
  • 【Bellman负环】Cycle Finding
  • (0️⃣基础)程序控制语句(初学者)(第3天)
  • 调用API接口返回参数缺失是什么原因导致的?
  • [3D数据存储] 对象 | OObject | IObject | 属性 | O<类型>Property | I<类型>Property
  • 安全基础DAY2-等级保护
  • linux-文件系统
  • AD8032ARZ-REEL7 ADI亚德诺 运算放大器 集成电路IC
  • 阿拉伯文识别技术:为连接古老智慧与数字未来铺设了关键道路