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.