How does scope lock work?

I am learning C ++, and I saw that the source code for locking the area is pretty simple. How does it work, and how is the “Resource Acquisition - Instantiation” (RAII) example?

+7
source share
3 answers

The idea of ​​RAII (resource initialization - initialization) is that the creation of an object and its initialization are combined into one inseparable action. This usually means that they are executed in the constructor of the objects.

Locked locks work by locking the mutex when they are constructed, and unlock it when they break. C ++ rules ensure that when a control flow leaves an area (even through an exception), objects local to the exit area are destroyed correctly. This means that instead of a local call to lock() and unlock() using a sliding lock, it is impossible not to accidentally unlock the mutex, for example. when an exception is thrown in the middle of the code between lock() and unlock() .

This principle applies to all resource acquisition scenarios to be released, and not just to locking mutexes. It is good practice to provide such “scope protection” classes for other operations with similar syntax.

For example, I recently worked on a data structure class that usually sends signals when it changes, but they must be disabled for some bulk operations. Providing an area protection class that disables them during construction and reenables them during destruction prevents potential unbalanced calls to the disconnect / enable functions.

+10
source

Here is a little code that illustrates locking with binding:

  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. This explains how scoped_lock works.

And this is how scoped_lock (minimal code) is usually implemented:

 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 } }; 
+15
source

It basically works as follows:

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

If you use it as

 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 validity period based on the area. Whenever the current volume remains and this lock is destroyed, it automatically calls mtx.unlock() . Note that in this particular example, mutex locking is implemented by the lock constructor, which is RAIII.

How do you do this without security? You will need to call mtx.unlock() when you leave this function. This is a) cumbersome and b) error prone. Also, you cannot release the mutex after returning without protecting the region.

+3
source

All Articles