9

我正在学习 C++,我看到作用域锁的源代码非常简单。. 它是如何工作的,这是“资源获取即实例化”(RAII)的一个例子吗?

4

3 回答 3

18

这是说明作用域锁的小代码:

 void do_something()
 {
    //here in the constructor of scoped_lock, the mutex is locked, 
    //and a reference to it is kept in the object `lock` for future use
     scoped_lock lock(shared_mutex_obj);

    //here goes the critical section code

}//<---here : the object `lock` goes out of scope
 //that means, the destructor of scoped_lock will run.
 //in the destructor, the mutex is unlocked.

阅读评论。这就解释了 scoped_lock 是如何工作的。

以下是scoped_lock通常的实现方式(最少的代码):

class scoped_lock : noncopyable
{
     mutex_impl &_mtx; //keep ref to the mutex passed to the constructor
   public:
      scoped_lock(mutex_impl & mtx ) : _mtx(mtx) 
      { 
          _mtx.lock();  //lock the mutex in the constructor
      }
      ~scoped_lock() 
      { 
         _mtx.unlock(); //unlock the mutex in the constructor
      }
};
于 2013-01-11T10:53:10.100 回答
13

RAII (Resource Acquisition Is Initialisation) 的理念是创建一个对象并对其进行初始化,这些操作结合在一起成为一个不可分割的动作。这通常意味着它们在对象的构造函数中执行。

作用域锁的工作原理是在构造互斥锁时锁定互斥锁,并在销毁互斥锁​​时解锁。C++ 规则保证当控制流离开作用域时(甚至通过异常),正在退出的作用域的本地对象被正确地破坏。这意味着使用范围锁而不是手动调用lock(),并且不可能意外地不解锁互斥锁,例如,当在和unlock()之间的代码中间抛出异常时。lock()unlock()

这个原则适用于所有获取需要释放的资源的场景,而不仅仅是锁定互斥锁。为具有类似语法的其他操作提供此类“范围保护”类是一种很好的做法。

例如,我最近研究了一个数据结构类,它通常在修改时发送信号,但是对于一些批量操作必须禁用这些。提供一个作用域保护类,在构造时禁用它们并在销毁时重新启用它们,防止对禁用/启用函数的潜在不平衡调用。

于 2013-01-11T10:57:06.157 回答
4

基本上它是这样工作的:

template <class Lockable>
class lock{
public:
    lock(Lockable & m) : mtx(m){
        mtx.lock();
    }
    ~lock(){
        mtx.unlock();
    }
private:
    Lockable & mtx;
};

如果你像这样使用它

int some_function_which_uses_mtx(){
    lock<std::mutex> lock(mtx);
    /* Work with a resource locked by mutex */
    if( some_condition())
        return 1;
    if( some_other_condition())
        return 1;
    function_witch_might_throw();
    return;
}

您创建一个具有基于范围的生命周期的新对象。每当离开当前范围并且该锁被销毁时,它将自动调用mtx.unlock(). 请注意,在此特定示例中,互斥锁上的锁是由lockRAIII 的构造函数获取的。

如果没有范围保护,您将如何做到这一点?mtx.unlock()每当您离开该功能时,您都需要致电。这是a) 麻烦和b) 容易出错的。此外,您不能在没有范围保护的情况下在返回后释放互斥锁。

于 2013-01-11T10:57:24.070 回答