c++ - 死锁使用 std::mutex 保护多线程中的 cout
问题描述
在多个线程中使用 cout 可能会导致交错输出。
所以我试图用互斥锁保护 cout 。
以下代码使用 std::async 启动 10 个后台线程。当一个线程启动时,它会打印“Started thread ...”。主线程按照创建的顺序遍历后台线程的未来,并在相应线程完成时打印出“Done thread ...”。
输出是正确同步的,但是在一些线程启动并且一些线程完成之后(见下面的输出),就会发生死锁。剩下的所有后台线程和主线程都在等待互斥锁。
僵局的原因是什么?
当 print 函数离开或 for 循环的一次迭代结束时,lock_guard 应该解锁互斥锁,以便等待线程之一能够继续。
为什么所有的线程都饿死了?
代码
#include <future>
#include <iostream>
#include <vector>
using namespace std;
std::mutex mtx; // mutex for critical section
int print_start(int i) {
lock_guard<mutex> g(mtx);
cout << "Started thread" << i << "(" << this_thread::get_id() << ") " << endl;
return i;
}
int main() {
vector<future<int>> futures;
for (int i = 0; i < 10; ++i) {
futures.push_back(async(print_start, i));
}
//retrieve and print the value stored in the future
for (auto &f : futures) {
lock_guard<mutex> g(mtx);
cout << "Done thread" << f.get() << "(" << this_thread::get_id() << ")" << endl;
}
cin.get();
return 0;
}
输出
Started thread0(352)
Started thread1(14944)
Started thread2(6404)
Started thread3(16884)
Done thread0(16024)
Done thread1(16024)
Done thread2(16024)
Done thread3(16024)
解决方案
您的问题在于使用future::get
:
当共享状态准备好时,返回存储在共享状态中的值(或抛出其异常)。
如果共享状态尚未准备好(即提供者尚未设置其值或异常),则该函数将阻塞调用线程并等待它准备好。
http://www.cplusplus.com/reference/future/future/get/
因此,如果未来的线程尚未运行,则该函数将阻塞,直到该线程完成。但是,您在调用 之前获得了互斥锁的所有权future::get
,因此您等待的任何线程都无法自己获得互斥锁。
这应该可以解决您的死锁问题:
int value = f.get();
lock_guard<mutex> g(mtx);
cout << "Done thread" << value << "(" << this_thread::get_id() << ")" << endl;
推荐阅读
- libgdx - 渲染多边形时Libgdx崩溃
- amazon-cognito - Cognito 身份 ID 持久性
- swift - UIDatePicker 在 macCatalyst 中不起作用(Xcode 11 Beta 5)
- ruby - 比较函数内的数组
- php - 如何在wordpress中递归解码简码
- react-native - 如何在反应原生快速图像中显示覆盖整个图像的灰色图像(而不是背景整个图像)
- haskell - 如何在 Haskell 上定义链表?
- php - (输入 [type='file'])值在提交表单后未显示
- node.js - 使用 React 在 Loopback 中设置访问令牌
- python - 熊猫计算数据框行中的日期差异