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

【C/C++】多线程下自旋锁的行为逻辑

文章目录

  • 多线程下自旋锁的行为逻辑
    • 1 自旋锁的基本逻辑
    • 2 线程状态分析
    • 3 自旋锁缺点
    • 4 自旋锁优化方式
    • 5 多核场景
    • 总结

多线程下自旋锁的行为逻辑

如果是自旋锁(spinlock)逻辑,当一个线程已经持有锁时,其他线程会不断尝试获取锁,处于“忙等(busy-waiting)”状态,不会主动休眠、挂起或进入阻塞态,除非你显式地这么写。


1 自旋锁的基本逻辑

std::atomic_flag lock = ATOMIC_FLAG_INIT;void lock_spin() {while (lock.test_and_set(std::memory_order_acquire)) {// 自旋:啥也不做,继续尝试获取锁}
}void unlock_spin() {lock.clear(std::memory_order_release);
}
  • test_and_set() 会原子地设置 locktrue,并返回旧值。
  • 如果另一个线程已设置 lock = true,那么当前线程会进入 while 循环 —— 这就是“忙等”。
  • 自旋期间线程不会释放 CPU,也不会进入 sleep 或 yield,仍然在占用计算资源。

2 线程状态分析

线程状态说明
持锁线程正常执行,直到 unlock()
自旋线程CPU 上循环尝试获取锁(高 CPU 占用),处于 Running 状态
阻塞线程不是自旋锁的行为,阻塞/挂起是互斥锁或条件变量做的事

在操作系统中,自旋线程的状态在调度器眼中通常是 “running”,如果被抢占则为 “ready”,而不是 “waiting” 或 “sleeping”。


3 自旋锁缺点

  • CPU 浪费大:线程处于忙等状态,浪费 CPU 周期。
  • 在多核下高竞争时非常低效。
  • 如果持锁线程长时间执行(或阻塞),自旋线程将毫无意义地消耗资源。

4 自旋锁优化方式

  1. 加上 pause/yield 提示 CPU 优化自旋:
while (lock.test_and_set(std::memory_order_acquire)) {std::this_thread::yield();  // Hint 给操作系统让出 CPU
}
  1. 自旋 + 回退 + sleep(适合高争用):
int count = 0;
while (lock.test_and_set(std::memory_order_acquire)) {if (++count > 1000) {std::this_thread::sleep_for(std::chrono::microseconds(10));  // 主动退让}
}

5 多核场景

  1. 可以有多个线程处于“运行态”吗?

可以有多个线程处于“就绪态(ready)”或“运行态(running)”,但实际同时运行的线程数量受限于 CPU 核心数。

  • 操作系统的线程调度器会维护多个状态:

    • Running:正在某个 CPU 核上执行。
    • Ready:准备好运行,但暂时没分配到 CPU。
    • Waiting/Sleeping/Blocked:在等 I/O、锁、条件变量等。
  • 如果你的系统是 4 核 CPU,那么最多可以同时运行 4 个线程(真正的并行)。

  • 其他线程即使“处于运行态”,但本质上是 ready 状态,被 OS 调度器等待调度。

  1. CPU 怎么决定“分配给谁”?
    由操作系统的 线程调度器(scheduler) 决定。调度策略有多种:
策略描述
时间片轮转(round-robin)每个线程轮流使用 CPU
优先级调度优先级高的线程更容易获得 CPU
多队列反馈结合线程运行情况动态调整优先级

调度器会考虑:

  • 线程优先级(nice 值、real-time 等)
  • 当前负载(load balancing)
  • CPU cache affinity(避免 cache miss)
  • 多核负载均衡(尽量让线程平均分布到各个核心)
  1. 多核 CPU 下的多线程运行模型
  • 多核 = 真正的“并行”执行

如果你有 8 核 CPU,你的 8 个线程可以真正在同一时间点并行执行,每个线程占用一个核心。线程之间通过共享内存、缓存一致性协议(如 MESI)等机制保持同步。

示例:4 个线程,4 核 CPU

时间核心 0核心 1核心 2核心 3
T0线程 A线程 B线程 C线程 D
T1线程 A线程 B线程 E线程 F

同时最多执行 4 个线程,剩下的在线程队列中等待调度。

  1. 自旋锁下,多线程抢锁是怎样的?
  • 每个核心上的线程在同时执行 while (lock.test_and_set()),此时所有核的线程都在自旋。
  • 哪个线程在某一时刻成功把 lock 从 false 设置为 true,它就赢得了执行权,进入临界区。
  • 其他线程仍然自旋,不会被挂起。
  1. 举个真实案例:8线程自旋 + 4核 CPU

  2. 线程 A 拿到自旋锁。

  3. 线程 B~H 也在尝试拿锁,它们会在各自 CPU 核或被调度时执行 while 自旋。

  4. 一旦线程 A 执行完 unlock(),调度器从剩下的线程中挑选一个抢锁成功。

  5. 其余线程继续自旋。


总结

情况自旋锁表现
锁未被持有线程获取锁,正常执行
锁被持有自旋线程持续运行,占用 CPU
高并发场景多线程争用,自旋浪费严重
最佳用途锁持有时间非常短的临界区,如 CPU 缓存级并发控制
问题回答
多个线程可以运行吗?可以,但并发度受限于 CPU 核数
谁获得 CPU 执行?操作系统调度器决定,基于策略
多核是怎么处理多线程的?各核独立运行线程,实现真正并行
自旋锁时线程状态?在运行或就绪态,不会自动 sleep
http://www.xdnf.cn/news/9222.html

相关文章:

  • C语言创意编程:用趣味实例玩转基础语法(2)
  • ES 在大查询场景下导致 GC 频繁,如何定位和解决?
  • webstorm调试vite工程(后端开发人员版)
  • 从十进制到二进制:深入理解定点数与浮点数表示
  • 高压单端探头,如何实现大比例的衰减?
  • 【NLP基础知识系列课程-Tokenizer的前世今生第二课】NLP 中的 Tokenizer 技术发展史
  • 【Vue3】生命周期 hook函数 toRef
  • 通义智文开源QwenLong-L1: 迈向长上下文大推理模型的强化学习
  • 浅解Vue 数据可视化开发建议与速度优化
  • 【华为云物联网】如何实现在 MQTT.fx 上模拟数据间隔上传一次,并按设定系数变动数据
  • HTML 表单与输入:基础语法到核心应用全解析
  • UBUNTU20.04 配置以QT界面程序代替系统界面启动,以及如何在tty模式下以linuxfb形式启动
  • Halcon 霍夫变换
  • 获取页面上当前激活(获得焦点)的元素
  • Frequent values/gcd区间
  • 行为型:中介者模式
  • C++11 中引入的`final` 关键字作用。
  • ImageMagick 是默认使用 CPU 来处理图像,也具备利用 GPU 加速的潜力
  • 数据库的事务(Transaction)
  • 路桥隧养护决策系统
  • atomic.Value 中存储的数据是否会被 GC
  • vue展示修改前后对比,并显示修改标注diff
  • 四足机器人环境监测系统相关问题
  • Mac 每日磁盘写入量异常高
  • AI如何颠覆财务预测?——用Python打造自动化智能分析系统
  • 基于Java,SpringBoot,Vue,UniAPP宠物洗护医疗喂养预约服务商城小程序管理系统设计
  • SQL Server 简介和与其它数据库对比
  • 联想小新笔记本电脑静电问题导致无法开机/充电的解决方案
  • 远程控制技术全面解析:找到适合你的最佳方案
  • 北京大学肖臻老师《区块链技术与应用》公开课:03-BTC-数据结构