现在我明白 Mutex 的目的是防止两个线程同时访问同一资源,但我没有看到 io_mutex 和 std::cout 之间的相关性。
std::cout
is a 全局对象,因此您可以将其视为共享资源。如果您从多个线程同时访问它,则这些访问必须以某种方式同步,以避免数据争用和未定义的行为。
通过考虑以下因素,您可能会更容易注意到并发访问的发生:
std::cout << x
实际上相当于:
::operator << (std::cout, x)
这意味着您正在调用一个在std::cout
对象,并且您同时从不同的线程执行此操作。std::cout
必须以某种方式受到保护。但这并不是唯一的原因scoped_lock
在那里(继续阅读)。
此代码是否只是锁定范围内的所有内容,直到范围完成为止?
是的,它锁了io_mutex
直到锁对象本身超出范围(作为典型的 RAII 包装器),这发生在 for 循环的每次迭代结束时。
为什么需要它?好吧,虽然在 C++11 中单独插入cout
保证是线程安全的,当多个线程输出某些内容时,后续的单独插入可能会交错。
请记住,每次插入operator <<
是一个单独的函数调用,就像您正在做的那样:
std::cout << id;
std::cout << ": ";
std::cout << i;
std::cout << endl;
事实是operator <<
返回流对象允许您将上述函数调用链接到单个表达式中(就像您在程序中所做的那样),但您有多个单独的函数调用的事实仍然成立。
现在看看上面的代码片段,更明显的是,这个作用域锁的目的是确保以下形式的每条消息:
<id> ": " <index> <endl>
打印时其部分不会与其他消息的部分交错。
另外,在 C++03 中(其中插入cout
are not保证是线程安全的),锁会保护cout
对象本身被同时访问。