gpt4 book ai didi

c++ - 将输出同步到 std::cout

转载 作者:太空狗 更新时间:2023-10-29 20:58:05 25 4
gpt4 key购买 nike

我有一个应用程序,其中多个线程写入 std::cout,我正在寻找一个简单的解决方案来防止发送到 std::cout 的数据被乱码。

例如,如果我有 2 个线程并且都输出:

std::cout << "Hello" << ' ' << "from" << ' ' << "thread" << ' ' << n << '\n';

我可能会看到这样的东西:

HelloHello from  fromthread  2
thread 1

我想看到的是:

Hello from thread 2
Hello from thread 1

线条的显示顺序不是很重要,只要它们不混淆即可。

我想到了以下相当简单的实现:

class syncstream : public std::ostringstream {
public:
using std::ostringstream::ostringstream;

syncstream& operator<<(std::ostream& (*pf)(std::ostream&) ) { pf(*this); return *this; }
syncstream& operator<<(std::ios& (*pf)(std::ios&) ) { pf(*this); return *this; }
syncstream& operator<<(std::ios_base& (*pf)(std::ios_base&)) { pf(*this); return *this; }

template<typename T>
syncstream& operator<<(T&& token) {
static_cast<std::ostringstream&>(*this) << std::forward<T>(token);
return *this;
}
};

inline std::ostream& operator&&(std::ostream& s, const syncstream& g) { return s << g.str(); }
#define synced(stream) stream && syncstream()

抱歉宏。

所以,现在在我的线程中我可以做:

synced(std::cout) << "Hello"  << ' ' << "from" << ' ' << "thread" << ' ' << n << '\n';

我写上面是因为我最初对§27.4.1的误解。但是,令人惊讶的是它的效果非常好。

我写了下面的测试用例:

void proc(int n) {
synced(std::cout) << "Hello" << ' ' << "world" << ' ' << "from" << ' ' << "thread" << ' ' << n << '\n';
}

int main() {
std::vector<std::thread> threads;
for(int n = 0; n < 1000; ++n) threads.push_back(std::thread(std::bind(proc, n)));

for(std::thread& thread: threads) thread.join();
return 0;
}

(完整版 here)并在我的系统上使用 g++ 4.8.3 和 clang++ 3.5.1(使用 libstdc++ 和 libc++)运行它。

测试是用 script 完成的,它运行测试用例 1000 次,生成 100 万行输出,然后解析输出以查找任何乱码行。

不能让它工作(即产生乱码)。

所以我的问题是:

为什么上述实现有效?

最佳答案

关于线程安全:从某种意义上说它是线程安全的不会引起数据竞争。但只要目标是其中之一标准流对象(std::cout 等),只要它们与 stdio 保持同步。这就是所有标准保证。和即便如此,您仍然可以得到交错的字符。

过去我不得不经常处理这个问题。我的解决方案有一直是一个包装类,带有指向实际的指针std::ostream,和一个模板:

template <typename T>
SynchedOutput& operator<<( T const& obj )
{
if ( myStream != nullptr ) {
(*myStream) << obj;
}
return *this;
}

SynchedOutput 的构造函数然后获取一个互斥锁,并且析构函数释放它,所以你可以这样写:

SynchedOutput( stream, mutex ) << ...;

(在我的例子中,我从一个函数中返回临时值,并且在 C++11 及其移动语义之前这样做,所以我的代码有点多复杂;我必须支持复制,并跟踪计数拷贝,这样我就可以在最后一个被破坏时解锁。今天,只需实现移动语义,无需复制,如果你想返回来自函数的实例。))

这里的问题是确保每个人都使用相同的互斥量。一可能是让构造函数在一个std::map 在流对象的地址上建立索引。这个查找需要一个全局锁,所以如果流对象没有。真正的问题是确保当流被破坏时,互斥量将从映射中删除。

关于c++ - 将输出同步到 std::cout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28660602/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com