C++ 在多个线程中使用 std::cout
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18277304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
using std::cout in multiple threads
提问by LxL
I write a simple program for testing Thread in c++11 but std::cout
doesnt work as I expect.
我写了一个简单的程序来测试 c++11 中的线程,但std::cout
没有按我预期的那样工作。
class Printer
{
public:
void exec()
{
mutex m;
m.lock();
cout<<"Hello "<<this_thread::get_id()<<endl;
chrono::milliseconds duration( 100 );
this_thread::sleep_for( duration );
m.unlock();
}
};
int main()
{
Printer printer;
thread firstThread([&printer](){
while(1)
printer.exec();
});
thread secondThread([&printer](){
while(1)
printer.exec();
});
firstThread.join();
secondThread.join();
}
some of the results :
一些结果:
Hello 11376
Hello 16076
Hello 16076
Hello Hello 11376
16076
Hello 11376
,....
I used mutex for locking threads so I cant understand why two threads are executing std::cout
at the same time.
It seams very weired to me.Can any one explain what is happening!?!
我使用互斥锁来锁定线程,所以我无法理解为什么两个线程同时执行std::cout
。我觉得很奇怪。谁能解释一下发生了什么!?!
回答by hmjd
The threads are using differentmutex
instances as the mutex
is a local variable in the exec()
function so locking the mutex
is pointless as each thread will be locking its own mutex
resulting in no synchronization between the threads. The same mutex
instance must be used by the threads to achieve synchronization.
线程使用不同的mutex
实例,因为mutex
是exec()
函数中的局部变量,因此锁定mutex
是没有意义的,因为每个线程都将锁定自己的,mutex
导致线程之间没有同步。mutex
线程必须使用相同的实例来实现同步。
To correct in the posted code, make the mutex
a member variable. However, if another Printer
object was created then there would be no synchronization between threads that used different Printer
instances. In this case, the mutex
would need to be a static
member variable to ensure synchronization:
要在发布的代码中进行更正,请创建mutex
成员变量。但是,如果Printer
创建了另一个对象,则使用不同Printer
实例的线程之间将不存在同步。在这种情况下,mutex
需要是一个static
成员变量以确保同步:
class Printer
{
public:
//...
private:
static std::mutex mtx_;
};
std::mutex Printer::mtx_;
To ensure a mutex
is always released, regardless if a function exits normally or via an exception, use std:lock_guard
:
为了确保 amutex
始终被释放,无论函数是正常退出还是通过异常退出,请使用std:lock_guard
:
std::lock_guard<std::mutex> lock(m); // 'm' locked, and will be
// unlocked when 'lock' is destroyed.
std::cout<< "Hello " << std::this_thread::get_id() << std::endl;
std::chrono::milliseconds duration( 100 );
std::this_thread::sleep_for( duration );
回答by Howard Hinnant
The accepted answer is correct. However it is nice to separate concerns:
接受的答案是正确的。但是,将关注点分开是很好的:
- You need a way to print to
std::cout
in a thread safe manner. - You need to create objects/functors/functions to run in threads and launch them.
- 您需要一种以
std::cout
线程安全的方式打印的方法。 - 您需要创建对象/函子/函数以在线程中运行并启动它们。
Here is a utility I use that just concentrates on collecting arguments to std::cout
and streaming them out under a static std::mutex
:
这是我使用的一个实用程序,它只专注于收集参数std::cout
并在 a 下将它们流式传输static std::mutex
:
#include <iostream>
#include <mutex>
std::ostream&
print_one(std::ostream& os)
{
return os;
}
template <class A0, class ...Args>
std::ostream&
print_one(std::ostream& os, const A0& a0, const Args& ...args)
{
os << a0;
return print_one(os, args...);
}
template <class ...Args>
std::ostream&
print(std::ostream& os, const Args& ...args)
{
return print_one(os, args...);
}
std::mutex&
get_cout_mutex()
{
static std::mutex m;
return m;
}
template <class ...Args>
std::ostream&
print(const Args& ...args)
{
std::lock_guard<std::mutex> _(get_cout_mutex());
return print(std::cout, args...);
}
This code can be reused for streams other than std::cout
, but the above is specialized to just target std::cout
. With this your Printer::exec()
can now be significantly simplified:
这段代码可以重用于流以外的流std::cout
,但上面的代码专门用于 target std::cout
。有了这个,您Printer::exec()
现在可以显着简化:
void exec()
{
print("Hello ", std::this_thread::get_id(), '\n');
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
Now, not only will your Printer
use cout
in a threadsafe manner, and has been simplified (e.g. doesn't need to maintain its own mutex
for cout
), but all of your other types and functions can also use cout
and all interoperate together safely. The print
function itself now maintains the mutex
, and that fact is encapsulated away from all of print
's clients.
现在,您的Printer
使用不仅会cout
以线程安全的方式进行,而且已经得到简化(例如,不需要维护自己的mutex
for cout
),而且您所有的其他类型和函数也可以cout
安全地使用并一起进行互操作。该print
函数本身现在维护mutex
,这实际上是从所有的封装远print
的客户。
回答by Conchylicultor
I'm sharing the trick from Nicolás given in this questionthat I find to be more elegant than Howard Hinnant implementation. The idea is to create a temporary ostringstream object and put the protection code on the destructor.
我正在分享 Nicolás 在这个问题中给出的技巧,我发现它比 Howard Hinnant 的实现更优雅。这个想法是创建一个临时的 ostringstream 对象并将保护代码放在析构函数上。
/** Thread safe cout class
* Exemple of use:
* PrintThread{} << "Hello world!" << std::endl;
*/
class PrintThread: public std::ostringstream
{
public:
PrintThread() = default;
~PrintThread()
{
std::lock_guard<std::mutex> guard(_mutexPrint);
std::cout << this->str();
}
private:
static std::mutex _mutexPrint;
};
std::mutex PrintThread::_mutexPrint{};
You can then use it as a regular std::cout
, from any thread:
然后,您可以std::cout
从任何线程将其用作常规:
PrintThread{} << "val = " << 33 << std::endl;
The object collect data as a regular std::ostringstream
. As soon the coma is reached, the object is destroyed and flush all collected information.
该对象定期收集数据std::ostringstream
。一旦达到昏迷,对象就会被销毁并刷新所有收集的信息。
回答by Walter
You may consider a global std::mutex cout_mutex;
(somewhere in your namespaces), which is used to protected std::cout
output. Make sure you use std::lock<std::mutex>
(so you cannot forget to unlock the mutex and for exception safety).
您可以考虑使用全局std::mutex cout_mutex;
(在您的命名空间中的某处),用于保护std::cout
输出。确保你使用std::lock<std::mutex>
(所以你不能忘记解锁互斥锁和异常安全)。