简体   繁体   中英

If a thread calls Acquire() on a critical section, will that lock be freed if a different thread calls Release()?

I'm using Embarcadero's critical section implementation, TCriticalSection, but their documentation doesn't answer my question.

If we have a global critical section object:

namespace
{
   //delphi style class must be constructed on the heap
   TCriticalSection* criticalSection = new TCriticalSection();
}

//somewhere in thread 1...
criticalSection->Acquire();

//somewhere in thread2...
criticalSection->Release();

Will the release call in thread2 open up the critical section?

I ask because I have RAII class which releases the lock during destruction, so we don't enter deadlock if the code throws an exception. However the critical section is only a part of the method.

//...
CRITICAL_SECTION_LOCK lock( criticalSection );
OneAtATimePlease();
lock.Release(); 
//...

So I don't want to put the critical section inside OneAtATimePlease() because then we'll be handling locks for every single call to that method in the code.

"Critical Section" is really a MS Windows concept. It's undefined what happens if a thread fails to unlock a critical section, and it is also undefined what happens if another thread tries to unlock a critical section it didn't lock.

What you suggest (another thread unlocking a critical section) is impossible because the locks are thread-local, even though the critical section is shared, and therefore each thread can only unlock its own lock.

TCriticalSection is a wrapper for a Win32 Critical Section object , where Acquire() simply calls EnterCriticalSection() , and Release() simply calls LeaveCriticalSection() .

The LeaveCriticalSection() documentation states:

A thread uses the EnterCriticalSection or TryEnterCriticalSection function to acquire ownership of a critical section object. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

So, DO NOT attempt to unlock the critical section in a thread that does not currently own the lock.

It is perfectly OK (and preferred) for you to move your lock variable inside of OneAtATimePlease() , where it belongs:

void OneAtATimePlease()
{
    CRITICAL_SECTION_LOCK lock( criticalSection );
    ...
}

Think about what would happen using your original code if multiple threads call OneAtATimePlease() at the same time but a thread DOES NOT lock the critical section:

Thread 1

CRITICAL_SECTION_LOCK lock( criticalSection );
OneAtATimePlease();
lock.Release();

Thread 2

CRITICAL_SECTION_LOCK lock( criticalSection );
OneAtATimePlease();
lock.Release();

Thread 3

// NO LOCK!!!
OneAtATimePlease();

Thread 3 could execute OneAtATimePlease() while Thread 1 or 2 are already inside of it! That defeats the whole purpose of using a critical section. If you move the lock inside of OneAtATimePlease() then there is no way for multiple threads to get out of sync with each other (unless one of them erroneously unlocks the critical section when it does not own the lock, but your RAII wrapper would prevent that).

This would even work recursively and safely, per the documentation :

When a thread owns a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. To release its ownership, the thread must call LeaveCriticalSection one time for each time that it entered the critical section.

void OneAtATimePlease()
{
    CRITICAL_SECTION_LOCK lock( criticalSection );
    ...
    if (some condition)
        OneAtATimePlease();
    ....
}

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