Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2612431
  • 博文数量: 877
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5921
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-05 12:25
个人简介

技术的乐趣在于分享,欢迎多多交流,多多沟通。

文章分类

全部博文(877)

文章存档

2021年(2)

2016年(20)

2015年(471)

2014年(358)

2013年(26)

分类: Windows平台

2015-05-14 14:41:24

How does scope-locking work?

I'm learning C++ and I saw that the source-code for a scope lock is quite simple. . How does it work, and how is this an example of "Resource Acquisition is Instantiation" (RAII) ?

shareimprove this question

3 Answers

up vote6down voteaccepted

The idea of RAII (Resource Acquisition Is Initialisation) is that creating an object and initialising it are joined together into one unseparable action. This generally means they're performed in the object's constructor.

Scoped locks work by locking a mutex when they are constructed, and unlocking it when they are destructed. The C++ rules guarantee that when control flow leaves a scope (even via an exception), objects local to the scope being exited are destructed correctly. This means using a scoped lock instead of manually calling lock() and unlock() makes it impossible to accidentally not unlock the mutex, e.g. when an exception is thrown in the middle of the code between lock() and unlock().

This principle applies to all scenarios of acquiring resources which have to be released, not just to locking mutexes. It's good practice to provide such "scope guard" classes for other operations with similar syntax.

For example, I recently worked on a data structure class which normally sends signals when it's modified, but these have to be disabled for some bulk operations. Providing a scope guard class which disables them at construction and re-enables them at destruction prevents potential unbalanced calls to the disable/enable functions.

shareimprove this answer

Here is the little code that illustrates scoped lock:

 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.

Read the comments. That explains how scoped_lock works.

And here is how scoped_lock is typically implemented (minimal code):

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 } };
shareimprove this answer
    
This is a fantastic answer, but I'm accepting @Angew because he also addressed the second part of my question about RAII. –  Jasper Blues Jan 11 '13 at 11:06

Basically it works like this:

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

If you use it like

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

you create a new object with a scope-based lifetime. Whenever the current scope is left and this lock gets destroyed it will automatically call mtx.unlock(). Note that in this particular example the lock on the mutex is aquired by the constructor of the lock, which is RAIII.

How would you do this without a scope guard? You would need to call mtx.unlock() whenever you leave the function. This is a) cumbersome and b) error-prone. Also you can't release the mutex after a return without a scope guard.

shareimprove this answer
阅读(439) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~