死锁使用std :: mutex来保护多线程中的cout

fra*_*nkk 12 c++ concurrency multithreading mutex deadlock

在多个线程中使用cout可能会导致交错输出.
所以我试图用互斥锁来保护cout.

以下代码使用std :: async启动10个后台线程.线程启动时,会打印"Started thread ...".主线程按照创建顺序迭代后台线程的未来,并在相应的线程完成时打印出"Done thread ...".

输出正确同步,但在某些线程启动后有些线程已经完成(参见下面的输出),就会出现死锁.剩下所有后台线程,主线程正在等待互斥锁.

僵局的原因是什么?

当保留打印功能或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;
}
Run Code Online (Sandbox Code Playgroud)

产量

Started thread0(352)
Started thread1(14944)
Started thread2(6404)
Started thread3(16884)
Done thread0(16024)
Done thread1(16024)
Done thread2(16024)
Done thread3(16024)
Run Code Online (Sandbox Code Playgroud)

Pas*_*eli 21

你的问题在于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;
Run Code Online (Sandbox Code Playgroud)


Ulr*_*rdt 11

您锁定互斥锁,然后等待其中一个期货,这反过来需要锁定互斥锁本身.简单规则:不要等待锁定的互斥锁.

BTW:锁定输出流不是很有效,因为它甚至无法控制的代码很容易被绕过.不是使用那些全局变量,而是为需要输出内容的代码(依赖注入)提供流,然后以线程安全的方式从该流中收集数据.或者使用日志库,因为这可能是你想要做的.