首页 > 解决方案 > 死锁使用 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)

标签: c++multithreadingconcurrencymutexdeadlock

解决方案


您的问题在于使用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;

推荐阅读