在现代 C++(自 C++11 起)中,有丰富的多线程工具可供使用:std::thread、互斥量和各种包装对象用于管理资源访问。线程之间安全交互需要理解以下组件:
为了避免竞争,始终在可能的情况下使用 RAII 包装类。请注意,尝试重复捕获同一互斥量会导致死锁(除非这是递归互斥量)。
正确工作的示例:
#include <iostream> #include <mutex> #include <thread> std::mutex mtx; void printThreadSafe(int id) { std::lock_guard<std::mutex> lock(mtx); std::cout << "Thread " << id << std::endl; } int main() { std::thread t1(printThreadSafe, 1); std::thread t2(printThreadSafe, 2); t1.join(); t2.join(); }
是否可以使用 std::lock_guardstd::mutex 来实现与 std::condition_variable 的条件同步?
回答: 不可以!使用 std::condition_variable 时必须使用 std::unique_lockstd::mutex,因为 lock_guard 不提供控制锁定的方法(例如,暂时释放 — unlock — 然后再重新捕获),而这在等待通知时是必需的。
示例:
std::mutex mtx; std::condition_variable cv; bool ready = false; void waitForEvent() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{return ready;}); // 后续处理 }
故事
项目中手动使用 mtx.lock()/mtx.unlock()。在 lock/unlock 之间抛出异常时,互斥量保持锁定状态,多个线程“挂起”。更换为 RAII(
std::lock_guard)后,问题消失。
故事
通过 std::condition_variable 通知时使用 std::lock_guard 而不是 std::unique_lock。结果,程序在新编译器上无法编译,在旧编译器上则由于 API 不一致而发生运行时断言。
故事
在代码中调用 std::lock_guard 的 unlock() 以进行“手动”控制对互斥量的访问。这导致在不同编译器上的未定义行为,有时会导致应用程序崩溃。意识到 lock_guard 不支持手动释放,需要迁移到 unique_lock。