互斥锁与自旋锁的区别

1. 生活中的例子

互斥锁vs自旋锁 ------ 门口排队vs不停敲门

可以代入一下,假设你去公司上厕所,发现厕所门是锁着的:

互斥锁(Mutex)的做法:

  • 你看到有人在里面,就去门口的椅子上坐着睡觉
  • 操作系统会把你这个"人(线程)"从CPU上移走,让CPU去做别的事情
  • 等里面的人出来了会叫醒你,你再进去

自旋锁(Spinlock)的做法

  • 你看到有人在里面,你不睡觉,就是在门口不停地敲门
  • 你一直占用着CPU,什么也不做,就循环检查"门开了没有"
  • 只要门一开,你就冲进去

2. 主要区别

特性 互斥锁(Mutex) 自旋锁(Spinlock)
等待方式 阻塞等待,线程休眠,让出CPU 忙着等,线程一直运行,占着CPU
上下文切换 有,线程休眠和唤醒都需要切换 无,一直运行在CPU上
性能开销 等待时间长时开销小 等待时间短时开销小
死锁风险 高(会导致线程永久休眠) 更高(会导致CPU占用100%)

3. 为什么会有这两种锁同时存在 ?

互斥锁的优缺点

  • 优点:等待时不占用CPU,适合长时间等待
  • 缺点:有上下文切换的开销,这个开销还是挺大的(大约几千个CPU周期)

自旋锁的优缺点

  • 优点:无上下文切换的开销,等待时间短时速度极快
  • 缺点:等待期间一直占用CPU,等待时间长了会浪费大量CPU资源

4. 怎么实现C++中的自旋锁 ?

C++标准库直到C++20才提供了官方的自旋锁 (std::spinlock)

  • 在C++11/C++14中,我们可以用std::atomic_flag自己实现一个自旋锁
cpp 复制代码
#include <atomic>
//C++11就能用的自旋锁实现
class Spinlock
{
private:
	//std::atomic_flag是唯一保证无锁的原子类型
    std::atomic_flag flag = ATOMIC_FLAG_INIT;

public:
    void lock()
    {
        // 循环尝试设置标记位直到成功
        // test_and_set() : 设置为true,返回之前的值
        while (flag.test_and_set(std::memory_order_acquire))
        {
            //什么也不做,一直占用CPU,这就是"自旋"
        }
    }
    
    void unlock()
    {
    	//清除标记位
        flag.clear(std::memory_order_release);
    }
};
相关推荐
青少儿编程课堂7 分钟前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
wo_jack2 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
青少儿编程课堂3 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
草莓熊Lotso3 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
David猪大卫21 小时前
【C++修炼】map 和 set 的使用
c语言·开发语言·数据结构·c++·经验分享·笔记·学习
HPtiger21 小时前
C++ 入门笔记:从 C 到 C++ 的核心过渡(命名空间、输入输出、缺省参数、重载、引用、内联)
c语言·c++·学习
努力努力再努力wz1 天前
【Lua 进阶系列】从 C++ 对象到 Lua 变量:一文理解 userdata、Lua 栈与元表绑定机制
c++·junit·lua
慧都产品智能化1 天前
Qt 表格升级攻略:复用已有编辑器,减少重复开发
c++·qt·编辑器·qt6.3
ShineWinsu1 天前
对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析
开发语言·c++·qt·gui·客户端·表格·qtablewidget
ShineWinsu1 天前
对于Qt:QListWidget常见属性以及QListWidgetItem类的解析
开发语言·c++·qt·客户端·列表·qlistwidget·qlistwidgetitem