On Fri, Feb 5, 2016 at 1:16 AM, Ben Coman <btc@openinworld.com> wrote:
On Wed, Feb 3, 2016 at 2:35 AM, Eliot Miranda <eliot.miranda@gmail.com> wrote:
Hi Ben,
On Tue, Feb 2, 2016 at 9:54 AM, Ben Coman <btc@openinworld.com> wrote:
While we are in the process of revising the Mutex infrastructure [1] to use dedicated primitives rather than rely on counting via a semaphore, I want to raise the question of simple versus recursive mutexes.
This isn't something I know much about, except that some people strongly believe recursive mutexes are evil, including David Butenhof who apparently was the guy who added recursive mutexes to POSIX "on a dare [...] but nobody was supposed to use recursive mutexes." [1].
There are two interesting discussion on stockoverflow [2][3]. But btw I disagree with Tall Jeff [3] says "The difference between a recursive and non-recursive mutex has to do with ownership. " I think he confuses a simple-mutex and binary-semaphore, as do a some commenters.
"Prefer Simple Mutex Over Recursive Mutex" [4] demonstrates some performance considerations and advises "a recursive mutex is dangerous because you lose sense of locking scope. It costs more than a simple mutex."
"Recursive Locks Will Kill You!" [5] provides some thread safety guidelines.
Finally, there is a paper "Ad Hoc Synchronization Considered harmful" [6], which I haven't read yet since I wanted to get this post out before heading to bed, but I hope to tomorrow.
[1] http://www.zaval.org/resources/library/butenhof1.html [2] http://stackoverflow.com/questions/2415082/when-to-use-recursive-mutex [3] http://stackoverflow.com/questions/187761/recursive-lock-mutex-vs-non-recurs... [4] http://askldjd.com/2009/10/26/prefer-simple-mutex-over-recursive-mutex/ [5] http://www.fieryrobot.com/blog/2008/10/14/recursive-locks-will-kill-you/ [6] https://www.usenix.org/legacy/event/osdi10/tech/full_papers/Xiong.pdf
So our existing Mutex implementation happens to be recursive, and I'm not suggesting we change that. However if we should consider *not* baking the *assumption* of recursion into the primitives, so the same primitives could *also* be used for a SimpleMutex class. The logic to provide recursion for Mutex is only [ owner = activeProcess ] which is easily done in-image.
So I propose introducing aquire/release primitives based off the existing critical section primitives with the recursion removed.
We have two sets of primitives, the queueing semaphore ones, signal and wait, #85 & #86, which are not recursive, and new ones, #185, #186 & #187 that support ownership, and hence support recursion. It makes no sense to remove the recursion support. That's what the primitives are for, to provide ownership support as efficiently as possible. Please don't be led by the problems others may have in other systems, and instead be led by how we're doing. Squeak and Pharo (and Smalltalk) have had recursive owned critical sections for decades and no one (e.g. from demanding industrial control applications) has complained that these recursive critical sections are problematic.
I respect your deep experience, but there is an engineering principle that "just because it works, doesn't mean its correct. It may just be reinforcing some misconceptions" ;)
Several reasons why people may not complain... 1. the expectation its been there so long that its correct 2. the expectation expert people worked on it so its correct 3. subtle bugs remain latent or trigger infrequently, thus hard to isolate 4. when bugs arise, they are fixed pragmatically without deeper philosophical consideration 5. coincidently other good programming practices avoided problematic situations 6. Threads run concurrently and co-operatively, so maybe in practice there are less issues than a parallel and pre-emptive systems.
Okay class... your new word for the day is "hubris". It was hubris for me to lay it out like that. It was easy to think I could do better from a distant hand waving perspective, but having spent a few hours in the trenches playing concretely with the primitive code, I've realised the current primitiveEnterCriticalSection is optimum.
I would think a thread doing an in-image (owner = activeProcess) test would be unaffected by suspension points since it doesn't change any state and only the same thread would have set owner via the primitive.
The new primitives give us a streamlined and hack-free implementation which doesn't depend on the niceties of what are suspension points as do the pre-primitive implementations. So I see no rationale for gelding these primitives.
You are right. Actually, as Dennis indicated, the existing primitive already provides everything needed... RecursiveMutex>>critical: aBlock ^self primitiveEnterCriticalSection ifTrue: [aBlock value] ifFalse: [aBlock ensure: [self primitiveExitCriticalSection]] SimpleMutex>>critical: aBlock ^self primitiveEnterCriticalSection ifTrue: [self error: 'recursive primitives will kill you'] ifFalse: [aBlock ensure: [self primitiveExitCriticalSection]] duh, me! Well, it was a useful learning process for me to play with the primitive. I'm may have some further thoughts on the exit primitive, but they are still forming, so I'll leave for a separate post. cheers -ben