uni*_*n83 3 c++ multithreading iostream stderr subclassing
什么是最简单的方法来创建我自己的,std::cerr
以便它是逐行线程安全的。
我最好寻找代码来做到这一点。
我需要的是,当我在控制台上实际看到它时(并且不与其他线程的输出混合),由一个线程生成的a line of output
(以 结尾std::endl
)保持不变as a line of output
。
解决方案:std::cerr
为多比cstdio慢。我更喜欢fprintf(stderr, "The message")
在CriticalSectionLocker
其构造函数获取线程安全锁而析构函数释放它的类内部使用。
如果可用,osyncstream (C++20) 解决了这个问题:
#include <syncstream> // C++20
std::osyncstream tout(std::cout);
std::osyncstream terr(std::cerr);
Run Code Online (Sandbox Code Playgroud)
如果上述功能不可用,这里有一个包含两个宏的插入头文件,用于线程安全写入std::cout
和std::cerr
(必须共享互斥锁以避免输出交错)。这些基于其他 两个答案,但我做了一些更改,以便轻松放入现有代码库。这适用于 C++11 及更高版本。
我已经用 4 核处理器上的 4 个线程对此进行了测试,每个线程每秒向 写入 25,000 行tout
并偶尔向 输出terr
,它解决了输出交错问题。与基于结构的解决方案不同,在放入此头文件时,我的应用程序没有可测量的性能损失。我能想到的唯一缺点是,由于这依赖于宏,因此不能将它们放入命名空间中。
线程流文件
#ifndef THREADSTREAM
#define THREADSTREAM
#include <iostream>
#include <sstream>
#include <mutex>
#define terr ThreadStream(std::cerr)
#define tout ThreadStream(std::cout)
/**
* Thread-safe std::ostream class.
*
* Usage:
* tout << "Hello world!" << std::endl;
* terr << "Hello world!" << std::endl;
*/
class ThreadStream : public std::ostringstream
{
public:
ThreadStream(std::ostream& os) : os_(os)
{
// copyfmt causes odd problems with lost output
// probably some specific flag
// copyfmt(os);
// copy whatever properties are relevant
imbue(os.getloc());
precision(os.precision());
width(os.width());
setf(std::ios::fixed, std::ios::floatfield);
}
~ThreadStream()
{
std::lock_guard<std::mutex> guard(_mutex_threadstream);
os_ << this->str();
}
private:
static std::mutex _mutex_threadstream;
std::ostream& os_;
};
std::mutex ThreadStream::_mutex_threadstream{};
#endif
Run Code Online (Sandbox Code Playgroud)
测试.cc
#include <thread>
#include <vector>
#include <iomanip>
#include "threadstream.h"
void test(const unsigned int threadNumber)
{
tout << "Thread " << threadNumber << ": launched" << std::endl;
}
int main()
{
std::locale mylocale(""); // get global locale
std::cerr.imbue(mylocale); // imbue global locale
std::ios_base::sync_with_stdio(false); // disable synch with stdio (enables input buffering)
std::cout << std::fixed << std::setw(4) << std::setprecision(5);
std::cerr << std::fixed << std::setw(2) << std::setprecision(2);
std::vector<std::thread> threads;
for (unsigned int threadNumber = 0; threadNumber < 16; threadNumber++)
{
std::thread t(test, threadNumber);
threads.push_back(std::move(t));
}
for (std::thread& t : threads)
{
if (t.joinable())
{
t.join();
}
}
terr << std::endl << "Main: " << "Test completed." << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译
g++ -g -O2 -Wall -c -o test.o test.cc
g++ -o test test.o -pthread
Run Code Online (Sandbox Code Playgroud)
输出
./test
Thread 0: launched
Thread 4: launched
Thread 3: launched
Thread 1: launched
Thread 2: launched
Thread 6: launched
Thread 5: launched
Thread 7: launched
Thread 8: launched
Thread 9: launched
Thread 10: launched
Thread 11: launched
Thread 12: launched
Thread 13: launched
Thread 14: launched
Thread 15: launched
Main: Test completed.
Run Code Online (Sandbox Code Playgroud)