2013-06-02 64 views
16

我是通过在drdobbs.com升压互斥教程阅读,发现这段代码:升压互斥锁作用域

#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; 
} 

现在我明白了一个互斥的一点是要防止两个线程访问同一资源,但我没有看到io_mutex和std :: cout之间的关联。这段代码是否锁定了范围内的所有内容,直到范围完成?

+5

是的,'scoped_lock'锁定互斥锁,直到范围退出。它有一个相当直观的名字。 – juanchopanza

+0

@juanchopanza我明白,scoped_lock的部分非常有意义。我没有得到的是互斥体和程序中其他任何东西之间的关系。它与程序中的执行顺序更相关,与实际内存相比更少?对不起,如果这是一个noob问题,但我一直在努力学习过去一周左右的互斥体,而没有得到它。 –

+0

@ jlw2387:正如我在回答中所写,'std :: cout'是一个全局对象,所以你可以将它看作一个共享资源。同时从不同线程访问共享资源需要同步。这就是'scoped_lock'的作用 –

回答

20

现在我明白了互斥体的意义在于防止两个线程同时访问相同的资源,但我没有看到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对象本身被同时访问。

+0

我不确定你是否已经明确指出互斥锁锁定了一个关键的代码区域---执行路径,而不是任何资源或对象。关于pre-C++ 11中'>>'的线程安全性:它取决于实现。有些是线程安全的。我对你的陈述感到惊讶,即std :: cout << i'在C++ 11中是线程安全的。我看不出有任何理由这样做。 (我也无法找到标准保证它的位置,但我也不知道在哪里看。) –

+1

@JamesKanze:在§27.4.1/ 4中有规定。 –

+0

我想知道为什么。它不会为你购买任何东西(正如你正确地指出的那样),它违背了图书馆其他地方使用的一般原则。 (更有用的方法是提供流的互斥成员,这样即使不知道彼此的库也可以同意互斥体的使用。) –

7

互斥量与程序 (条件变量除外)中的任何其他值无关,至少在更高的级别上。 互斥锁有两个效果:它控制程序流程,并防止多个线程同时执行同一个代码块 。它也确保了内存同步。这里的 的一个重要问题是互斥锁与 资源没有关联,并且不妨碍两个线程同时访问相同的资源。互斥量定义了代码的关键部分 ,该代码一次只能由一个线程输入。如果 所有对特定资源的使用都在由相同互斥锁控制的关键 部分中完成,那么该资源是由互斥锁有效保护的 。但是编码器建立的关系是 ,通过确保所有使用都在位置处于关键部分。