我正在阅读drdobbs.com上的Boost Mutex教程,并发现了这段代码:
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}
现在我明白Mutex的意思是阻止两个线程同时访问同一个资源,但我没有看到io_mutex和std :: cout之间的相关性。在范围完成之前,此代码是否只锁定范围内的所有内容?
答案 0 :(得分:21)
现在我明白Mutex的意思是阻止两个线程同时访问同一个资源,但我没有看到io_mutex和std :: cout之间的相关性。
std::cout
是全局对象,因此您可以将其视为共享资源。如果从多个线程同时访问它,则必须以某种方式同步这些访问,以避免数据争用和未定义的行为。
通过考虑以下内容,您可能会更容易注意到并发访问:
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
的插入> 保证是线程安全的),锁将保护cout
对象本身不被保护同时访问。
答案 1 :(得分:8)
互斥锁与程序中的任何其他内容无关 (条件变量除外),至少在更高的水平。 互斥锁有两个作用:它控制程序流,并防止 多个线程执行相同的代码块 同时。它还确保了内存同步。该 这里重要的问题是,互斥体与之无关 资源,并不阻止两个线程访问相同的 资源在同一时间。互斥锁定义了一个临界区 代码,一次只能由一个线程输入。如果 特定资源的所有使用都是关键的 由相同的互斥锁控制的部分,然后资源是 有效地受互斥锁保护。但这种关系是 由编码员建立,确保所有使用确实需要 放在关键部分。