(C++) 笔记 C++11 std::mutex std::condition_variable 的使用
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int main() {
constexpr size_t kLoopNum = 10;
std::mutex mtx;
std::condition_variable cv;
bool ready_flag{false};
std::thread thd_producer([&]() {
for (size_t i = 0; i < kLoopNum; i++) {
std::cout << "producer thread " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (!ready_flag) {
std::unique_lock<std::mutex> lock;
ready_flag = true;
cv.notify_one();
}
}
});
std::thread thd_consumer([&]() {
for (size_t i = 0; i < kLoopNum; i++) {
std::cout << "consumer thread " << i << std::endl;
std::unique_lock<std::mutex> lock;
cv.wait(lock, [&]() {
return !ready_flag;
});
}
});
thd_producer.join();
thd_consumer.join();
}
输出信息:
producer thread 0
consumer thread 0
consumer thread 1
consumer thread 2
consumer thread 3
consumer thread 4
consumer thread 5
consumer thread 6
consumer thread 7
consumer thread 8
consumer thread 9
producer thread 1
producer thread 2
producer thread 3
producer thread 4
producer thread 5
producer thread 6
producer thread 7
producer thread 8
producer thread 9
使用解读
如下 a, b 用法等效
std::unique_lock <std::mutex> lck(mtx);
// cv.wait(lck, [&](){return ready;}); // (a)
while(!ready) cv.wait(lck); // (b)
条件变量ready必须位于lock中,以保证内存序
cpp reference: conditional_variable
Even if the shared variable is atomic, it must be modified under the mutex in order to correctly publish the modification to the waiting thread.
Any thread that intends to wait on std::condition_variable has to
- acquire a std::unique_lockstd::mutex, on the same mutex as used to protect the shared variable
- either A
2.1 check the condition, in case it was already updated and notified
2.2 execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
2.3 When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.
or B
use the predicated overload of wait, wait_for, and wait_until, which takes care of the three steps above
C++11中的lock
- std::unique_lock
- std::lock_guard
- std::scoped_lock
- std::lock
C++11中的lock都属于资源自动管理(RAII)范畴。
unique_lock 在使用上比lock_guard更具有弹性,和 lock_guard 相比,unique_lock 主要的特色在于:
- unique_lock 不一定要拥有 mutex,所以可以透过 default constructor 建立出一个空的 unique_lock。
- unique_lock 虽然一样不可复制(non-copyable),但是它是可以转移的(movable)。所以,unique_lock 不但可以被函数回传,也可以放到 STL 的 container 里。
- 另外,unique_lock 也有提供 lock()、unlock() 等函数,可以用来加锁解锁mutex,也算是功能比较完整的地方。
- unique_lock本身还可以用于std::lock参数,因为其具备lock、unlock、try_lock成员函数,这些函数不仅完成针对mutex的操作还要更新mutex的状态。
conditional_variable的notidy
- cv.notify_one
- cv.notify_all
- std::notify_all_at_thread_exit(...)
参考
分类:
C++
标签:
C++ / template
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构