Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happen if 2 threads do EnterCriticalSection and thread 1 do DeleteCriticalSection

I am hunting a possible deadlock in my program and im suspecting the following. What happen if 2 threads at the same time calls EnterCriticalSection and thread #1 calls DeleteCriticalSection right after entering, what happen to thread #2 which is still in EnterCriticalSection call?

Thanks.

like image 898
user1727542 Avatar asked Oct 08 '12 01:10

user1727542


People also ask

What is the maximum number of threads that could be waiting to access the critical section?

No more than one thread can be in its critical section at any one time. A thread which dies in its critical non-critical section will not affect the others' ability to continue.

What is critical section stack overflow?

Critical section is a code chunk. If any thread entered it, no other thread can enter until it's free. If 1 and 2 are different critical sections (i.e. handled by a different semaphore), someone can enter 2 if 1 is occupied.


1 Answers

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

Two threads cannot enter the critical section at the same time. That would defeat the purpose of a critical section. Either Thread #1 enters the critical section first, or Thread #2 enters the critical section first. You have two possible interleavings at play here.

Let's say that the interleaving is this:

    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

Remarks

Deleting a critical section object releases all system resources used by the object.

After a critical section object has been deleted, do not reference the object in any function that operates on critical sections (such as EnterCriticalSection, TryEnterCriticalSection, and LeaveCriticalSection) other than InitializeCriticalSection and InitializeCriticalSectionAndSpinCount. If you attempt to do so, memory corruption and other unexpected errors can occur.

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

So if you're unlucky enough for your two threads to encounter the above interleaving, then the operating system gives you no guarantee that your program will continue to work as expected. That can include deadlocking Thread #2, for example.

But if the interleaving is this:

    Thread 1               Thread 2
    --------               --------
       |                      |
       |                      |
       |                   EnterCS()
       |                   Lock Taken
       |                      |
    EnterCS()                 |
    Blocked                   |
       |                      |
       |                      |
       |                   ExitCS()
       |                   Lock Released
       |                      |
    Unblocked                 |
    LockTaken                 |
       |                      |
    DeleteCS()                |
       |                      |
       |                      |
      ...                    ...

Then obviously, since Thread #1 is blocked, it can't 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 with no problems.

The scenario that you propose is essentially a race condition. Depending on the timing of the threads, it may work just fine or cause unpredictable problems. In this case, you have to restructure your code such that the destruction of the critical section happens after all interested threads have released the critical section.

In this two-thread scenario, one way to fix it is to have Thread #1 leave the critical section and wait for all the other threads to finish first 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, the two possible interleavings look like this:

    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() is going to depend on the nature of your program, but would certainly involve WaitForSingleObject() or any one of its relatives.

like image 51
In silico Avatar answered Oct 19 '22 21:10

In silico