This looks racy to me, can someone explain where I’m going wrong?
Thread A is the first to acquire the benephore, checks and increments the atomic variable, finds it is zero and proceeds without acquiring the semaphore.
While Thread A is in the critical section Thread B arrives and acquires the benephore, finds the atomic variable to be non-zero so acquires the semaphore. Because it has the semaphore it proceeds into the critical section. Now there are two threads concurrently in the critical section.
I think you’re right, unless I’m missing something obvious.
Worse still, if T1 enters the critical section and is followed by T2, if T1 now makes progress it will find benaphore_atom > 1 and call release_sem() on a semaphore it doesn’t hold. Which is probably either a crash or UB, who knows.
I was missing something obvious.
The semaphore, is initialized into an ‘unavailable’ state.
When Thread B attempts to acquire the newly initialized semaphore, it blocks as the semaphore is in its ‘unavailable’ state.
Thread A later finishes up in its Critical Section, and seeing that benaphore_atom > 1 it increments the semaphore, allowing Thread B to make progress.
At the end of this execution, T2 sees !(benaphore_atom > 1) and continues without marking the semaphore as available.
You use them to e.g. count the number of items in a queue and wake up enough threads to process them. Then those threads use a separate mutex to synchronise any operations on the queue.
This looks racy to me, can someone explain where I’m going wrong?
Thread A is the first to acquire the benephore, checks and increments the atomic variable, finds it is zero and proceeds without acquiring the semaphore.
While Thread A is in the critical section Thread B arrives and acquires the benephore, finds the atomic variable to be non-zero so acquires the semaphore. Because it has the semaphore it proceeds into the critical section. Now there are two threads concurrently in the critical section.
What prevents this scenario?
I think you’re right, unless I’m missing something obvious.Worse still, if T1 enters the critical section and is followed by T2, if T1 now makes progress it will findbenaphore_atom > 1and callrelease_sem()on a semaphore it doesn’t hold. Which is probably either a crash or UB, who knows.I was missing something obvious.
The semaphore, is initialized into an ‘unavailable’ state.
When Thread B attempts to acquire the newly initialized semaphore, it blocks as the semaphore is in its ‘unavailable’ state. Thread A later finishes up in its Critical Section, and seeing that
benaphore_atom > 1it increments the semaphore, allowing Thread B to make progress.At the end of this execution, T2 sees
!(benaphore_atom > 1)and continues without marking the semaphore as available.Semaphores don’t provide mutual exclusion.
You use them to e.g. count the number of items in a queue and wake up enough threads to process them. Then those threads use a separate mutex to synchronise any operations on the queue.