использование 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> (поэтому вы не можете забыть разблокировать мьютекс и для безопасности исключений).