Semaphore and Mutex changes summary
Hi. We got interesting discussion about semaphore and mutex. Here I put summary of proposed changes. First we will deprecate Semaphore>>forMutualExclusion and rename it to Semaphore>>newSignalled. Explanation from Ben Coman: Semaphore>>forMutualExclusion *encourages* people to believe
semaphores can be used *on*their*own* for mutual exclusion, when they *shouldn't*. You *must* add ownership. If the mutual exclusion object doesnât have ownership then, irrelevant of what it is called, it is not a mutex!!! [1].
And more:
With an implementation like.. Semaphore>>forMutualExclusion ^self new signal we don't gain a lot, and its a misleading convenience method since its doesn't provide the proper facility for mutual exclusion (and I do conflate mutual exclusion == mutex). Indeed, "Semaphore forMutualExclusion + roll your ownership management + problems since you weren't aware you needed to roll your own ownership management" is not more convenient than "Mutex new" If you want to keep a convenience method for a pre signalled Semaphore, then we could provide something like "Semaphore newSignalled"
It is also explain why we should deprecate Semaphore>>critical: and use Mutex>>critical: instead. That's second change. So we want to move 4 Semaphore methods to Mutex: - critical: mutuallyExcludedBlock It will relies on new Semaphore method waitIfInterrupted: which block is executed when waiting process terminated at point where lock was not acquired. Slice for this already in inbox. - critical: mutuallyExcludedBlock ifCurtailed: terminationBlock - critical: mutuallyExcludedBlock ifError: errorBlock Semantic of this method is like BlockCosure>>ifError:. It culls error properties to handler block. It will be changed to cull only error instance. It will touch WeakArray and WeakRegistry. Now they doing this: ifError:[:msg :rcvr| rcvr error: msg]. No special logic inside handler. So we will just use #critical: message. - critical: mutuallyExcludedBlock ifLocked: alternativeBlock It purpose looks like "enter critical section without waiting otherwise alternativeBlock". But implementation not shows that waiting can not be happens: critical: mutuallyExcludedBlock ifLocked: alternativeBlock excessSignals == 0 ifTrue: [ ^alternativeBlock value ]. ^self critical: mutuallyExcludedBlock When critical message is sent but it method not started interrupt can happen and other process can lock this semaphore. And when process will be resumed it will be blocked. So implementation is not correct to me. It should be changed somehow. Welcome for suggestions
thanks for the summary. I think that this is important to update the class comments with the comment of ben. I read several blogs of mutex vs semaphore and this is nice to get this cleared out. Stef Le 7/1/16 14:05, Denis Kudriashov a écrit :
Hi.
We got interesting discussion about semaphore and mutex. Here I put summary of proposed changes.
First we will deprecate Semaphore>>forMutualExclusion and rename it to Semaphore>>newSignalled. Explanation from Ben Coman:
Semaphore>>forMutualExclusion *encourages* people to believe semaphores can be used *on*their*own* for mutual exclusion, when they *shouldn't*. You *must* add ownership. If the mutual exclusion object doesnât have ownership then, irrelevant of what it is called, it is not a mutex!!! [1].
And more:
With an implementation like.. Semaphore>>forMutualExclusion ^self new signal we don't gain a lot, and its a misleading convenience method since its doesn't provide the proper facility for mutual exclusion (and I do conflate mutual exclusion == mutex). Indeed, "Semaphore forMutualExclusion + roll your ownership management + problems since you weren't aware you needed to roll your own ownership management" is not more convenient than "Mutex new" If you want to keep a convenience method for a pre signalled Semaphore, then we could provide something like "Semaphore newSignalled"
It is also explain why we should deprecate Semaphore>>critical: and use Mutex>>critical: instead. That's second change.
So we want to move 4 Semaphore methods to Mutex:
* critical: mutuallyExcludedBlock
It will relies on new Semaphore method waitIfInterrupted: which block is executed when waiting process terminated at point where lock was not acquired. Slice for this already in inbox.
* critical: mutuallyExcludedBlock ifCurtailed: terminationBlock * critical: mutuallyExcludedBlock ifError: errorBlock
Semantic of this method is like BlockCosure>>ifError:. It culls error properties to handler block. It will be changed to cull only error instance. It will touch WeakArray and WeakRegistry. Now they doing this:
ifError:[:msg :rcvr| rcvr error: msg].
No special logic inside handler. So we will just use #critical: message.
* critical: mutuallyExcludedBlock ifLocked: alternativeBlock
It purpose looks like "enter critical section without waiting otherwise alternativeBlock". But implementation not shows that waiting can not be happens:
critical: mutuallyExcludedBlock ifLocked: alternativeBlock excessSignals == 0 ifTrue: [ ^alternativeBlock value ]. ^self critical: mutuallyExcludedBlock
When critical message is sent but it method not started interrupt can happen and other process can lock this semaphore. And when process will be resumed it will be blocked. So implementation is not correct to me. It should be changed somehow.
Welcome for suggestions
I found the blogs by real-time OS guys (RTOS) have more interesting opinions on the finer points. They are the ones who are down in the trenches. cheers -ben On Sat, Jan 9, 2016 at 4:17 AM, stepharo <stepharo@free.fr> wrote:
thanks for the summary. I think that this is important to update the class comments with the comment of ben. I read several blogs of mutex vs semaphore and this is nice to get this cleared out.
Stef
Le 7/1/16 14:05, Denis Kudriashov a écrit :
Hi.
We got interesting discussion about semaphore and mutex. Here I put summary of proposed changes.
First we will deprecate Semaphore>>forMutualExclusion and rename it to Semaphore>>newSignalled. Explanation from Ben Coman:
Semaphore>>forMutualExclusion *encourages* people to believe semaphores can be used *on*their*own* for mutual exclusion, when they *shouldn't*. You *must* add ownership. If the mutual exclusion object doesnât have ownership then, irrelevant of what it is called, it is not a mutex!!! [1].
And more:
With an implementation like.. Semaphore>>forMutualExclusion ^self new signal we don't gain a lot, and its a misleading convenience method since its doesn't provide the proper facility for mutual exclusion (and I do conflate mutual exclusion == mutex). Indeed, "Semaphore forMutualExclusion + roll your ownership management + problems since you weren't aware you needed to roll your own ownership management" is not more convenient than "Mutex new" If you want to keep a convenience method for a pre signalled Semaphore, then we could provide something like "Semaphore newSignalled"
It is also explain why we should deprecate Semaphore>>critical: and use Mutex>>critical: instead. That's second change.
So we want to move 4 Semaphore methods to Mutex:
critical: mutuallyExcludedBlock
It will relies on new Semaphore method waitIfInterrupted: which block is executed when waiting process terminated at point where lock was not acquired. Slice for this already in inbox.
critical: mutuallyExcludedBlock ifCurtailed: terminationBlock critical: mutuallyExcludedBlock ifError: errorBlock
Semantic of this method is like BlockCosure>>ifError:. It culls error properties to handler block. It will be changed to cull only error instance. It will touch WeakArray and WeakRegistry. Now they doing this:
ifError:[:msg :rcvr| rcvr error: msg].
No special logic inside handler. So we will just use #critical: message.
critical: mutuallyExcludedBlock ifLocked: alternativeBlock
It purpose looks like "enter critical section without waiting otherwise alternativeBlock". But implementation not shows that waiting can not be happens:
critical: mutuallyExcludedBlock ifLocked: alternativeBlock excessSignals == 0 ifTrue: [ ^alternativeBlock value ]. ^self critical: mutuallyExcludedBlock
When critical message is sent but it method not started interrupt can happen and other process can lock this semaphore. And when process will be resumed it will be blocked. So implementation is not correct to me. It should be changed somehow.
Welcome for suggestions
Le 9/1/16 03:04, Ben Coman a écrit :
I found the blogs by real-time OS guys (RTOS) have more interesting opinions on the finer points. They are the ones who are down in the trenches.
Yes I read them too even if I got lost probably :)
cheers -ben
On Sat, Jan 9, 2016 at 4:17 AM, stepharo <stepharo@free.fr> wrote:
thanks for the summary. I think that this is important to update the class comments with the comment of ben. I read several blogs of mutex vs semaphore and this is nice to get this cleared out.
Stef
Le 7/1/16 14:05, Denis Kudriashov a écrit :
Hi.
We got interesting discussion about semaphore and mutex. Here I put summary of proposed changes.
First we will deprecate Semaphore>>forMutualExclusion and rename it to Semaphore>>newSignalled. Explanation from Ben Coman:
Semaphore>>forMutualExclusion *encourages* people to believe semaphores can be used *on*their*own* for mutual exclusion, when they *shouldn't*. You *must* add ownership. If the mutual exclusion object doesnât have ownership then, irrelevant of what it is called, it is not a mutex!!! [1]. And more: With an implementation like.. Semaphore>>forMutualExclusion ^self new signal we don't gain a lot, and its a misleading convenience method since its doesn't provide the proper facility for mutual exclusion (and I do conflate mutual exclusion == mutex). Indeed, "Semaphore forMutualExclusion + roll your ownership management + problems since you weren't aware you needed to roll your own ownership management" is not more convenient than "Mutex new" If you want to keep a convenience method for a pre signalled Semaphore, then we could provide something like "Semaphore newSignalled"
It is also explain why we should deprecate Semaphore>>critical: and use Mutex>>critical: instead. That's second change.
So we want to move 4 Semaphore methods to Mutex:
critical: mutuallyExcludedBlock
It will relies on new Semaphore method waitIfInterrupted: which block is executed when waiting process terminated at point where lock was not acquired. Slice for this already in inbox.
critical: mutuallyExcludedBlock ifCurtailed: terminationBlock critical: mutuallyExcludedBlock ifError: errorBlock
Semantic of this method is like BlockCosure>>ifError:. It culls error properties to handler block. It will be changed to cull only error instance. It will touch WeakArray and WeakRegistry. Now they doing this:
ifError:[:msg :rcvr| rcvr error: msg].
No special logic inside handler. So we will just use #critical: message.
critical: mutuallyExcludedBlock ifLocked: alternativeBlock
It purpose looks like "enter critical section without waiting otherwise alternativeBlock". But implementation not shows that waiting can not be happens:
critical: mutuallyExcludedBlock ifLocked: alternativeBlock excessSignals == 0 ifTrue: [ ^alternativeBlock value ]. ^self critical: mutuallyExcludedBlock
When critical message is sent but it method not started interrupt can happen and other process can lock this semaphore. And when process will be resumed it will be blocked. So implementation is not correct to me. It should be changed somehow.
Welcome for suggestions
2016-01-07 14:05 GMT+01:00 Denis Kudriashov <dionisiydk@gmail.com>:
It is also explain why we should deprecate Semaphore>>critical: and use Mutex>>critical: instead. That's second change.
So we want to move 4 Semaphore methods to Mutex:
- critical: mutuallyExcludedBlock
It will relies on new Semaphore method waitIfInterrupted: which block is executed when waiting process terminated at point where lock was not acquired. Slice for this already in inbox.
It was wrong idea. I stop slice for the better solution. I will post about it later
participants (3)
-
Ben Coman -
Denis Kudriashov -
stepharo