多核系统中基于事件的系统如何处理多线程同时触发的并发事件?
多线程并发提交事件队列的解决方案
核心要解决的是多线程并行写入队列的原子性问题,避免两个线程同时操作队列的同一个存储位置导致数据覆盖、结构损坏,具体实现可以按优先级选以下方案:
1. 有锁队列实现(开发成本最低,兼容性最好)
- 给事件队列绑定一个互斥锁(mutex),所有工作线程完成计算要提交事件时,必须先申请持有这个互斥锁,同一时间只会有一个线程拿到锁
- 持有锁的线程完成完整的事件入队操作(写入分片单词计数、分片ID等全量元数据)后,立即释放锁,后续等待的线程再依次抢占锁完成写入
- 该方案几乎所有编程语言的标准库都有原生支持,不需要额外开发,适合90%以上的常规场景
- 示例代码(C++):
#include <queue> #include <mutex> #include <condition_variable> // 分片计数结果结构体 struct ShardResult { int shard_id; long word_count; }; std::queue<ShardResult> result_queue; std::mutex queue_mtx; std::condition_variable new_event_signal; // 工作线程调用的提交接口 void submit_shard_result(ShardResult res) { // 自动加锁,函数退出时自动释放,避免异常导致死锁 std::lock_guard<std::mutex> lock(queue_mtx); result_queue.push(res); // 通知主线程有新结果待处理 new_event_signal.notify_one(); }
2. 无锁队列实现(性能更高,适合高并发场景)
- 如果工作线程数量超过16个、事件提交频率超过每秒10万次,可以采用无锁队列实现,基于CPU原生提供的CAS(比较并交换)原子指令完成入队操作
- 不需要加锁就能保证多线程同时写入时不会出现数据覆盖,性能比有锁队列高20%~40%,缺点是不同语言需要找成熟的第三方实现,自行开发容易出隐蔽bug
补充优化点
- 提交的事件里必须带上分片的唯一ID,主线程汇总时可以校验所有分片是否都返回结果,避免乱序入队导致的漏统计
- 有锁实现中不要在持有锁的阶段做任何耗时操作(比如日志打印、额外计算),尽量只保留入队操作,减少锁的持有时间,降低多线程等待开销
内容的提问来源于stack exchange,提问作者theprogrammer311
相关产品推荐
相关产品推荐

