跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
C++ 条件变量
”︁(章节)
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= C++条件变量 = '''条件变量'''(Condition Variable)是C++多线程编程中用于线程间同步的重要机制,它允许线程在特定条件满足前挂起等待,并在条件可能满足时被唤醒。条件变量通常与互斥锁(mutex)配合使用,是生产者-消费者模型、线程池等并发模式的核心组件。 == 基本概念 == 条件变量解决了线程间通信的"等待-通知"问题。其核心思想是: * 线程A检查条件,若条件不满足则等待(原子地释放锁并进入休眠) * 线程B修改条件后通知等待线程 * 线程A被唤醒后重新获取锁并验证条件 C++标准库提供<code>std::condition_variable</code>(需<code>#include <condition_variable></code>)和<code>std::condition_variable_any</code>两种实现。 == 核心方法 == {| class="wikitable" ! 方法 !! 描述 |- | <code>notify_one()</code> || 唤醒一个等待线程 |- | <code>notify_all()</code> || 唤醒所有等待线程 |- | <code>wait(lock)</code> || 原子地解锁并等待,被唤醒后重新获取锁 |- | <code>wait(lock, predicate)</code> || 带条件的等待(推荐用法) |- | <code>wait_for()</code> || 带超时的等待 |- | <code>wait_until()</code> || 带绝对时间点的等待 |} == 基本用法示例 == 以下展示一个简单的生产者-消费者模型: <syntaxhighlight lang="cpp"> #include <iostream> #include <thread> #include <mutex> #include <condition_variable> #include <queue> std::mutex mtx; std::condition_variable cv; std::queue<int> data_queue; void producer() { for (int i = 0; i < 5; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::lock_guard<std::mutex> lock(mtx); data_queue.push(i); std::cout << "Produced: " << i << std::endl; cv.notify_one(); // 通知一个消费者 } } void consumer() { while (true) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return !data_queue.empty(); }); // 等待队列非空 int data = data_queue.front(); data_queue.pop(); std::cout << "Consumed: " << data << std::endl; lock.unlock(); if (data == 4) break; // 结束条件 } } int main() { std::thread t1(producer); std::thread t2(consumer); t1.join(); t2.join(); return 0; } </syntaxhighlight> '''输出示例:''' <pre> Produced: 0 Consumed: 0 Produced: 1 Consumed: 1 ... Produced: 4 Consumed: 4 </pre> == 虚假唤醒与条件检查 == 条件变量可能因系统原因出现'''虚假唤醒'''(spurious wakeup),因此必须: 1. 总是使用带有谓词(predicate)的wait版本 2. 或者在循环中检查条件 正确做法对比: <syntaxhighlight lang="cpp"> // 错误:可能虚假唤醒 cv.wait(lock); // 正确:使用谓词 cv.wait(lock, []{ return ready; }); // 正确:循环检查 while (!ready) { cv.wait(lock); } </syntaxhighlight> == 线程同步状态图 == <mermaid> stateDiagram [*] --> 等待条件 等待条件 --> 获取锁: notify_one/all 获取锁 --> 检查条件 检查条件 --> 等待条件: 条件不满足 检查条件 --> 执行操作: 条件满足 执行操作 --> [*] </mermaid> == 高级主题 == === 1. 条件变量与锁的选择 === * <code>std::condition_variable</code> 只能与<code>std::unique_lock<std::mutex></code>配合使用 * <code>std::condition_variable_any</code> 可与任何满足BasicLockable要求的锁配合 === 2. 性能考虑 === * 通知操作(notify)通常不持有锁以获得更好性能 * 批量处理时可优先使用<code>notify_all()</code> === 3. 与future/promise的区别 === 条件变量适用于多对多线程通信,而future/promise适用于一次性事件通知。 == 实际应用案例 == '''案例:有限资源池''' 实现一个限制最大并发数的线程池: <syntaxhighlight lang="cpp"> class ThreadPool { std::mutex mtx; std::condition_variable cv; int active_threads = 0; const int max_threads; public: ThreadPool(int max) : max_threads(max) {} void execute(std::function<void()> task) { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, [this]{ return active_threads < max_threads; }); active_threads++; lock.unlock(); std::thread([this, task]{ task(); std::lock_guard<std::mutex> lock(mtx); active_threads--; cv.notify_one(); }).detach(); } }; </syntaxhighlight> == 常见问题 == '''Q: 为什么条件变量需要互斥锁?''' A: 因为条件的检查与修改必须是原子操作,防止竞态条件。 '''Q: notify_one()和notify_all()如何选择?''' A: 当只有一个等待线程能满足条件时用notify_one(),多个可能满足时用notify_all()。 '''Q: 条件变量会自己记住通知吗?''' A: 不会。如果在没有线程等待时调用notify,通知会被丢弃(与信号量不同)。 == 数学原理 == 条件变量的行为可以用'''管程'''(Monitor)理论描述: <math> \begin{cases} \text{wait} & : \text{释放锁} \rightarrow \text{进入等待队列} \\ \text{notify} & : \text{从等待队列移入就绪队列} \\ \text{notifyAll} & : \text{所有等待线程移入就绪队列} \end{cases} </math> == 最佳实践 == 1. 总是使用RAII管理锁(如<code>lock_guard</code>、<code>unique_lock</code>) 2. 通知前尽量释放锁 3. 优先使用带谓词的wait版本 4. 避免在持有锁时执行耗时操作 5. 考虑使用<code>std::atomic</code>简化简单场景 [[Category:C++多线程]] [[Category:C++标准库]] [[Category:编程语言]] [[Category:C++]] [[Category:C++ 多线程]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)