1

我如何锁定我的线程,使我的输出不是这样的:你好...你好...hheelhllelolo.l..o......

std::size_t const nthreads=5;
std::vector<std::thread> my_threads(nthreads);

for(unsigned i=0;i<nthreads;i++)
{
    my_threads[i] = std::thread ([] () {std::cout << "hello...";}); 
}
4

2 回答 2

9

标准说:

多个线程对同步 (27.5.3.4) 标准 iostream 对象的格式化和未格式化输入 (27.7.2.1) 和输出 (27.7.3.1) 函数或标准 C 流的并发访问不应导致数据竞争 (1.10)。[注意:如果用户希望避免交错字符,则仍必须同步多个线程对这些对象和流的并发使用。—结束注释]
                                                                                        — [iostream.objects.overview] 27.4.1 p4

请注意,不产生数据竞争的要求仅适用于标准 iostream 对象(cout、cin、cerr、clog、wcout、wcin、wcerr 和 wclog)并且仅在它们同步时(默认情况下它们是同步的,并且可以使用 sync_with_stdio 成员函数禁用)。

不幸的是,我注意到了两种现象;实现要么提供比要求更严格的保证(例如,所有流对象的线程同步,无论如何,性能都很差)或更少(例如,标准流对象是 sync_with_stdio 产生数据竞争)。MSVC 似乎倾向于前者,而 libc++ 倾向于后者

无论如何,如注释所示,如果要避免交错字符,则必须自己提供互斥。这是一种方法:

std::mutex m;

struct lockostream {
    std::lock_guard<std::mutex> l;
    lockostream() : l(m) {}
};

std::ostream &operator<<(std::ostream &os, lockostream const &l) {
    return os;
}

std::cout << lockostream() << "Hello, World!\n";

这样,使用 std::cout 创建了一个锁守卫并在表达式的持续时间内存在。您可以将 lockostream 对象模板化以适用于任何 basic_*stream,甚至适用于流的地址,这样您就可以为每个对象设置一个单独的互斥锁。

当然,标准流对象是全局变量,因此您可能希望像避免使用所有全局变量一样避免它们。它们对于学习 C++ 和玩具程序很方便,但您可能希望为真正的程序安排更好的东西。

于 2012-09-26T19:22:20.570 回答
2

您必须像使用任何其他资源一样使用正常的锁定技术,否则您会遇到 UB。

std::mutex m;
std::lock_guard<std::mutex> lock(m);
std::cout << "hello hello";

或者你可以使用printf哪个是线程安全的(在posix上):

printf("hello hello");
于 2012-09-26T17:19:28.260 回答