C++ 11中的基本线程锁定

Ale*_*lex 1 c++ multithreading locking c++11

如何锁定我的线程,以便我的输出不是这样的:你好......你好...... 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...";}); 
}
Run Code Online (Sandbox Code Playgroud)

bam*_*s53 7

标准说:

并发访问同步(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";
Run Code Online (Sandbox Code Playgroud)

这样就可以使用std :: cout在表达式的持续时间内创建一个锁定保护程序.您可以将lockostream对象模板化以适用于任何basic_*流,甚至可以在流的地址上工作,这样您就可以为每个对象分配一个互斥锁.

当然,标准流对象是全局变量,因此您可能希望以避免所有全局变量的方式避免它们.它们对于学习C++和玩具程序很方便,但您可能希望为实际程序安排更好的东西.