简体   繁体   中英

Is Locking CCriticalSection more than once in same thread good practice?

In a MFC Application, I have 2 threads accessing my data, So I am using CCriticalSection Lock and Unlock to protect my data not to be acessed from 2 threads simultaneously.

From One of the thread I need to lock my data twice,

Thread 1,

  void ProcessFunction()
  {
         LockData();                  // LockData and unLockData internally uses CCriticalSection
         if( IsDataAvailable() )
         {

         }
         UnLockData();
  }

Already IsDataAvialable has LockData()

   IsDataAvailable()
   {
     LockData();
     bool bAvailable = .....;
     UnLockData();
     return bAvialble;
   }

Thread 2

     void Delete() 
     {
        LockData();

        ....
        UnLockData();
     }

When I tested the Second Lock from Thread 1 is not waiting for first Lock to call unlock,

But one Lock from a thread is waiting for another thread to call unlock.

I understood Lock of one thread will wait for Lock count to become 0 by another thread. But it won't wait for the same thread to unlock if locked by same thread. This is the expected behaviour.

I want to know whether calling Lock more than once in same thread is good practice or not?

The term of art you may be looking for here is "recursive mutex" or "reentrant mutex." The question is, does CCriticalSection support recursive locking (locking when already locked in the same thread)? And from what I can tell (eg http://microsoft.public.vc.mfc.narkive.com/gjxzQaHf/ccriticalsection ), it does.

Here's an interesting discussion about recursive mutexes, which says you should not use them: http://www.zaval.org/resources/library/butenhof1.html

This is called a "recursive lock".

Some people don't like them. You have written a function IsDataAvailable() that is sometimes called with the lock held and sometimes called when it isn't held. In this case it doesn't need to know which because it takes the lock across everything it does, but it's still somewhat dangerous to write functions like that. Code that does locking should know what locks are already held in order to use locks correctly. Examples include avoiding locking inversion, and to ensure that if you need to release a lock (for example when using condition variables) that you can do so without creating problems for your caller who thought the lock was held the whole time.

You can always satisfy the people who don't like recursive locks, by writing two versions of IsDataAvailable() : one to calculate the value without locking, and another one that takes the lock, calls the first, and releases the lock. Then call the "right" one in any given context.

This can end up creating quite a lot of variant functions, though. If you use recursive locks correctly there's nothing really wrong with them, so you have to judge whether the additional work will help you to always use your locks correctly.

Using recursive locking has use cases, but this isn't one of them... So no, this is not good practice. 99% of the time thread safety should not be done inside an object (or conceptual object, which might be your case) so that the object can be used in different threads which are outside the object.

This is a matter of separation of concerns and the generic use of your objects. data may need to be used single threaded sometime, in which case you don't want locks on all these operations. Even if that isn't the case, conceptually data belongs in data , and if you want to safely use data across multiple threads you should handle that elsewhere.

Separating these concepts opens up lots of flexibility: You can use different kinds of locking, like shared_mutex , etc. You can use the same lock for manipulating multiple objects.

This might seem like it will dirty up your code with locking everywhere. That's somewhat true. There are patterns you can use to help... like monitor .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM