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

线程从共享队列取任务的底层机制

基本架构概览

text

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   线程1     │    │   线程2     │    │   线程3     │
└──────┬──────┘    └──────┬──────┘    └──────┬──────┘│                  │                  │▼                  ▼                  ▼
┌─────────────────────────────────────────────────┐
│              共享任务队列 (Shared Queue)          │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐   │
│  │ 任务1 │ │ 任务2 │ │ 任务3 │ │ 任务4 │ │ 任务5 │   │
│  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘   │
└─────────────────────────────────────────────────┘│▼
┌─────────────────────────────────────────────────┐
│           同步原语 (锁、条件变量等)               │
└─────────────────────────────────────────────────┘

底层同步机制

1. 互斥锁 (Mutex)

cpp

std::mutex queue_mutex;// 取任务时的锁保护
std::unique_lock<std::mutex> lock(queue_mutex);
if (!task_queue.empty()) {Task task = task_queue.front();task_queue.pop();
}
lock.unlock();

2. 条件变量 (Condition Variable)

cpp

std::condition_variable cv;
std::mutex queue_mutex;// 消费者线程等待任务
std::unique_lock<std::mutex> lock(queue_mutex);
while (task_queue.empty()) {cv.wait(lock);  // 释放锁并等待通知
}
// 队列不为空,取任务
Task task = task_queue.front();
task_queue.pop();
lock.unlock();

内存屏障与原子操作

内存可见性保证

cpp

// 不使用原子操作 - 可能有问题
bool has_task = false;  // 普通bool,可能缓存导致可见性问题// 使用原子操作 - 保证可见性
std::atomic<bool> has_task{false};

底层CPU指令

  • LOCK前缀:x86架构中确保指令的原子性

  • MFENCE:内存屏障指令,保证内存操作顺序

  • CAS (Compare-And-Swap):无锁队列的核心

无锁队列实现

基于CAS的无锁队列

cpp

template<typename T>
class LockFreeQueue {struct Node {T data;std::atomic<Node*> next;};std::atomic<Node*> head;std::atomic<Node*> tail;public:void enqueue(const T& value) {Node* new_node = new Node{value, nullptr};Node* old_tail = tail.load();while (!tail.compare_exchange_weak(old_tail, new_node)) {// CAS失败,重试}// ... 其他逻辑}
};

线程调度的底层影响

1. 上下文切换开销

cpp

// 当线程等待时,发生上下文切换
cv.wait(lock);  // → 线程进入等待状态 → 调度器选择其他线程运行

2. 缓存局部性

  • 缓存命中:频繁访问的任务队列可能在CPU缓存中

  • 缓存失效:多核CPU中,不同核心访问同一数据导致缓存同步

3. 虚假唤醒 (Spurious Wakeup)

cpp

// 必须使用循环检查,不能使用if
while (task_queue.empty()) {  // 正确:循环检查cv.wait(lock);
}// if (task_queue.empty()) {   // 错误:可能虚假唤醒
//     cv.wait(lock);
// }

性能优化技术

1. 批量取任务

cpp

std::vector<Task> batch_tasks;
{std::lock_guard<std::mutex> lock(queue_mutex);for (int i = 0; i < batch_size && !task_queue.empty(); ++i) {batch_tasks.push_back(task_queue.front());task_queue.pop();}
}
// 处理批量任务,减少锁竞争

2. 工作窃取 (Work Stealing)

cpp

// 每个线程有自己的队列,空闲时从其他线程队列"窃取"任务
class WorkStealingQueue {std::deque<Task> local_queue;std::vector<WorkStealingQueue*> all_queues;public:bool try_steal(Task& task) {// 尝试从其他队列窃取任务for (auto* queue : all_queues) {if (queue != this && queue->try_pop_back(task)) {return true;}}return false;}
};

实际执行流程

text

线程执行取任务流程:
1. 获取互斥锁 (可能自旋或阻塞等待)
2. 检查队列状态↓ 队列为空├── 等待条件变量 (释放锁,线程进入睡眠)│   └── 被唤醒后重新获取锁,再次检查↓ 队列不为空├── 从队列移除任务└── 释放互斥锁
3. 处理任务 (无锁状态下)
4. 返回步骤1

总结

线程从共享队列取任务的底层涉及:

  • 同步原语:互斥锁、条件变量保证线程安全

  • 内存模型:原子操作、内存屏障保证可见性

  • CPU调度:上下文切换、缓存优化影响性能

  • 高级优化:无锁数据结构、工作窃取提升并发度

http://www.dtcms.com/a/561215.html

相关文章:

  • 一站式网站建设报价怎样做商城网站
  • 宜春公司网站建设网页改进方案
  • 「经典数字题」集合 | C/C++
  • centos7实测
  • 【3DV 进阶-5】3D生成中 Inductive Bias (归纳偏置)的技术路线图
  • HOT100题打卡第26天——动态规划
  • 第五章 二项式系数
  • 制作网站语言网络营销方法有什么
  • 合肥网站建站推广从零开始做电影网站
  • 电商Web 渗透测试小小清单
  • 做信息流推广需要建立网站么最基本的网站设计
  • 基于双向时序卷积网络与门控循环单元(BiTCN-GRU)混合模型的时间序列预测MATLAB代码
  • DevOps(devops/k8s/docker/Linux)学习笔记-2
  • 三点水网站建设wordpress wp-polls
  • 用数据照亮成长之路:PandaCoder Git 统计工具窗口
  • FPGA的LVDS接口电压
  • 【每天一个AI小知识】:什么是Embedding?
  • 南昌网站排名优化免费提供空间的网站
  • 三种服务生命周期
  • Mybatis的添加和修改功能
  • Linux 安全文件传输完全指南:sftp 与 scp 的深度解析引言
  • Mysql基础3
  • 上海cms网站建设珠海网站建设 科速
  • 有没有可以做游戏的网站电商网课教材
  • 【自然语言处理】生成式语言模型GPT复现详细技术方案
  • Qt 打开文件列表选择文件,实现拖拽方式打开文件,拖拽加载
  • 网站搭建徐州百度网络搭建专做婚礼logo的网站
  • macOS 上获取调试版
  • 奉加微PHY6230软件三:自定义MAC和ll_set_ble_mac_addr不能屏蔽
  • 模型推理如何利用非前缀缓存