использование std::cout в нескольких потоках
Я пишу простую программу для тестирования потока в 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();
}
результаты :
Hello 11376
Hello 16076
Hello 16076
Hello Hello 11376
16076
Hello 11376
,....
я использовал мьютекс для блокировки потоков, поэтому я не могу понять, почему два потока выполняются std::cout
в то же время.
Его швы очень weired для меня.Может кто-нибудь объяснить, что происходит!?!
4 ответов
принятый ответ правильный. Однако приятно разделять заботы:
- вам нужен способ для печати
std::cout
потокобезопасным способом. - вам нужно создать объекты / функторы / функции для запуска в потоках и запуска их.
вот утилита, которую я использую, которая просто концентрируется на сборе аргументов для std::cout
и потоковое их под 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...);
}
этот код можно повторно использовать для потоков других чем 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));
}
теперь не только Printer
использовать cout
в threadsafe образом, и был упрощен (например, не нужно поддерживать свой собственный mutex
на cout
), но все ваши другие типы и функции также могут использовать cout
и все взаимодействуют вместе безопасно. The print
сама функция теперь поддерживает mutex
, и этот факт инкапсулированный от всего print
клиенты.
Я разделяю трюк от Николаса дал в этот вопрос что я считаю более элегантным, чем реализация Говарда Хиннанта. Идея состоит в том, чтобы создать временный объект 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{};
затем вы можете использовать его как обычный std::cout
, из любого потока:
PrintThread{} << "val = " << 33 << std::endl;
объект собирает данные как обычный std::ostringstream
. Как только кома достигается, объект разрушается и смывается все собранное информация.
вы можете рассмотреть глобальный std::mutex cout_mutex;
(где-то в ваших пространствах имен), который используется для protected std::cout
выход. Убедитесь, что вы используете std::lock<std::mutex>
(поэтому вы не можете забыть разблокировать мьютекс и для безопасности исключений).