Is Entrance into a Windows Critical Section an atomic operation?
You read done
outside the critical section. That is a race condition. If you want to look at the value of done
, you need to do it before you leave
the critical section.
You might see a write to done
from another thread, triggering the assert
before the write to criticalValue
is visible to the thread that saw the write to done
.
If the critical section protects criticalValue
and done
, then it is an error to access either of them without being in the critical section unless you are sure every thread that might access them has terminated. Your code violates this rule.
providing critical section for threads in c++
Just use two counters and a boolean to implement a basic "take a number" scheme.
One counter, released_thread
, indicates which thread may proceed. This is logically equivalent to the "now serving" indicator.
The other, next_waiter
, indicates which thread waits next. This is logically equivalent to the next number that will be taken
A boolean indicates whether the thread is permitted to proceed and when it is finished, so the executive knows when to call the next number.
The algorithms are as follows:
To wait:
Acquire the lock.
Note the value of the
next_waiter
variable and increment it.Broadcast (notify all) the condition variable.
Wait on the condition variable until the boolean is true and the
released_thread
counter is equal to the value noted in step 2.Release the lock.
When finished, acquire the lock, set the boolean to false, broadcast the condition variable, and release the lock.
Executive:
Acquire the lock.
Wait on the condition variable until the boolean is false and
next_waiter
is not equal toreleased_thread
.Increment
released_thread
and set the boolean to true.Broadcast the condition variable.
Go to step 2.
Fairness: Where can it be better handled?
There has been research done on revoking ownership of mutexes in order to ensure equal sharing or to detect and avert deadlock. However, this really is overkill and not worth the effort, especially since it opens up a whole new can of worms such as how a program should behave if it was in the midst of some computation and it lost ownership of its resources. It's really up to the application to ensure that its various threads play fair with with each other and consume resources in a way that won't deadlock.
I should point out that there is another option, albeit of a slightly different variety, and that is the use of the message passing style of parallel programming. With message passing, the synchronization is all implicit in the communication; no explicit synchronization is required, which helps to avert such errors.
Synchronization between threads using Critical Section
The real problem here is "ThreadA is always in critical section". ThreadA should not be locking the critical section indefinitely.
In C#, your code for ThreadA would look something like:
Message message;
// Only lock critical section for the time it takes to modify the queue
lock(_messageQueueLock){
message = _messageQueue.Dequeue();
}
// do something with the message
In my opinion, the following general rules of thumb should be observed when using critical sections:
- Enter and exit the critical section as quickly as possible (i.e. minimize the amount of code in the critical section).
- Use critical sections to protect a resource/asset (e.g. shared memory, queue, list, etc.)
- Avoid using critical sections to protect function/method calls. If you are making function/method calls from within a critical section... you are increasing the probability of creating deadlocks.
- Avoid trying to lock a critical section from within a critical section. Failing to do so may result in potential deadlocks within your application.
- Avoid trying to access an external resource (e.g. executing a database SQL query) while in a critical section.
- Where it makes sense, I generally like to use the following naming convention for critical sections: if the asset that is being protected is called
messageQueue
... then I would name the critical sectionmessageQueueLock
Great quote from Microsoft: "When you use multithreading of any sort, you potentially expose yourself to very serious and complex bugs" [SOURCE: MSDN]
Same critical section being called in function and subfunction
Is my analysis correct and does this mean that it's advised to have different critical sections for main and sub functions?
From Microsoft Docs (emphasis mine):
After a thread has ownership of 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. The thread enters the critical section each time
EnterCriticalSection and TryEnterCriticalSection succeed. A thread
must call LeaveCriticalSection once for each time that it entered the
critical section.
So no, what you described should not happen. It is perfectly fine to enter the critical section multiple times and it is required to leave it exactly as many times.
Related Topics
One Command to Create a Directory and File Inside It Linux Command
Refresh Net.Core.Somaxcomm (Or Any Sysctl Property) for Docker Containers
Linux Dlopen: Can a Library Be "Notified" When It Is Loaded
Linux Zip Command: Add a File with Different Name
Is Nice() Used to Change the Thread Priority or the Process Priority
Setitimer, Sigalrm & Multithread Process (Linux, C)
Using Opengl Without X-Window System
Using 'Find' to Return Filenames Without Extension
How to Transfer the Data of Columns to Rows (With Awk)
Rename Files in Multiple Directories to the Name of the Directory
Gurus Say That Ld_Library_Path Is Bad - What's the Alternative
Why Can't Files Be Manipulated by Inode
Munmap() Failure with Enomem with Private Anonymous Mapping
Bash VS Csh VS Others - Which Is Better for Application Maintenance
Why Can't You Sleep While Holding Spinlock