What happens if 2 threads have EnterCriticalSection and thread 1 do DeleteCriticalSection

I am looking for a possible deadlock in my program, and I suspect the following. What happens if two threads call EnterCriticalSection at the same time, and thread # 1 calls DeleteCriticalSection right after input, what happens with thread # 2, which is still in the EnterCriticalSection call?

Thanks.

+4
source share
1 answer

What happens if 2 threads call EnterCriticalSection at the same time and thread # 1 calls DeleteCriticalSection right after input, what happens with thread # 2, which is still in the EnterCriticalSection call?

Two threads cannot enter the critical section at the same time. This will violate the purpose of the critical section. Either thread No. 1 first enters the critical section, or the first thread enters the critical section. There are two possible interceptions.

Let's say that alternation is:

  Thread 1 thread 2
     -------- --------
        |  |
        |  |
     EnterCS () |
     Lock Taken |
        |  |
        |  EnterCS ()
        |  Blocked
        |  |
        |  |
     DeleteCS () |
        |  |
        |  ???
        |
       ...

In this case, the state of thread # 2 is undefined according to MSDN :

DeleteCriticalSection Function

Notes

Removing the critical section object frees the entire system of resources used by the object.

After the critical section object has been deleted, do not reference the object in any function that works with critical sections (for example, EnterCriticalSection, TryEnterCriticalSection and LeaveCriticalSection), except for InitializeCriticalSection and InitializeCriticalSectionAndSpinCount. If you try to do this, memory corruption and other unforeseen errors.

If a critical section is deleted while it still belongs, the state of the threads is waiting for ownership of the remote critical section undefined.

So, if you are unlucky for your two threads to encounter the aforementioned rotation, then the operating system gives you no guarantee that your program will continue to work as expected. For example, this may include Thread # 2 lock.

But if alternation is:

  Thread 1 thread 2
     -------- --------
        |  |
        |  |
        |  EnterCS ()
        |  Lock taken
        |  |
     EnterCS () |
     Blocked |
        |  |
        |  |
        |  ExitCS ()
        |  Lock released
        |  |
     Unblocked |
     LockTaken |
        |  |
     DeleteCS () |
        |  |
        |  |
       ... ...

Then, obviously, since Thread # 1 is locked, it cannot delete the critical section until Thread # 2 leaves the critical section. Then, assuming no other threads enter the critical section, Thread # 1 will be able to delete it without problems.

The scenario you are proposing is essentially a race condition. Depending on the timing of the threads, it may work fine or cause unpredictable problems. In this case, you should rebuild your code so that the destruction of the critical section occurs after all interested threads have released the critical section.

In this two-threaded scenario, one way to fix this is that Thread # 1 leaves the critical section and waits for all other threads to complete before deleting the critical section. Something like this, for example:

// Pseudocode for exposition void Thread1() { EnterCS(); // Do stuff ExitCS(); WaitForThread2(); DeleteCS(); } void Thread2() { EnterCS(); // Do stuff ExitCS(); } 

Now two possible interlaces are as follows:

  Thread # 2 acquires lock first:.  Thread # 1 acquires lock first:
                                     .
     Thread 1 Thread 2.  Thread 1 thread 2
     -------- --------.  -------- --------
        |  |  .  |  | 
        |  EnterCS ().  EnterCS () |
        |  Lock Taken  Lock Taken |
        |  |  .  |  |
     EnterCS () |  .  // Do stuff EnterCS ()          
     Blocked // Do stuff.  |  Blocked
        |  |  .  |  |
        |  |  .  ExitCS () |
        |  ExitCS ().  Lock Released |
        |  Lock Released  |  |
        |  |  .  |  Unblocked
     Unblocked |  .  |  Lock taken
     Lock Taken |  .  |  |
        |  |  .  |  // Do stuff
    // Do stuff |  .  |  |
        |  |  .  |  ExitCs ()
     ExitCS () |  .  |  Lock released
     Lock Released |  .  |  |
        |  |  .  |  |
        |  |  .  |  |
     WaitForThread2 () - +.  WaitForThread2 () - +
        |  .  |
     DeleteCS ().  DeleteCS ()
        |  .  |
        |  .  |
       done.  done

The exact implementation for WaitForThread2() will depend on the nature of your program, but it will necessarily include WaitForSingleObject() or any of its relatives.

+12
source

Source: https://habr.com/ru/post/1438317/


All Articles