What happen if 2 threads do EnterCriticalSection and thread 1 do DeleteCriticalSection
Asked Answered
J

1

7

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.

Jiva answered 8/10, 2012 at 1:49 Comment(3)
Not exactly true since DeleteCriticalSection will delete the memory and EnterCriticalSection should throw an access violation exception. Except in my case it doesnt throw an exception, i get a deadlock.Jiva
The documentation disagrees with you: "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."Irradiate
First I assume thread#1 will not be calling LeaveCriticalSection if it is planning on deleting it. however, thread#2 blocked while waiting for it is now in undefined state behavior and as such cannot be reliable. Bottom line: don't do this. Make sure all threads have left both ownership and wait-for-ownership conditions before deleting it and you'll be fine.Autum
I
14

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.

Irradiate answered 8/10, 2012 at 1:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.