On Tue, 12 Jun 2007 05:42:02 +0900, “Nasir K.” [email protected]
wrote:
While the comparison is against Java synchronization, does the
Mutex#synchronize has the same behavior as synchronized in Java?
Roughly speaking, yes.
end
The keyword “synchronized” in Java implies not just locking but perhaps
more importantly “synchronization” of the current thread’s working memory with
heap. [JLS 17.4]
i.e. memory barriers.
It’s probably better to compare Mutex#lock and Mutex#unlock with the JVM
monitorenter and monitorexit instructions, since Java’s synchronized
translates to a single pair of monitorenter and monitorexit instructions
on the JVM.
In JRuby, a call to each of #lock and #unlock involves both monitorenter
and monitorexit, so Mutex#synchronize is actually slightly more
aggressive than Java synchronized in terms of its memory effects.
However, the portable assumption is probably still only that it is no
less aggressive than the JVM.
I can understand the behavior of JRuby but how would the other Ruby
interpreters be implemented for such things?
In practice, implementors defer to whatever the underlying platform is;
under those circumstances, the only option for programmers is to adopt a
very conservative posture towards locking and memory model.
If one were to implement a Ruby interpreter today where should he/she
start in the absence of a language spec? Take MRI as the spec? But MRI may
not be addressing all the issues like the one in question here.
Indeed – it doesn’t. Though I suppose one could reasonably say that
MRI, with its green threads, effectively fences all reads and writes,
but that’s obviously a bit heavy-handed to actually implement.
Yes, but even the volatile keyword doesn’t do what you expect. Despite
widespread folklore, volatile by itself is not sufficient to ensure
thread safety – you need to use operations which include memory barriers
(generally by using the provided synchronization primitives).
BTW the folklore is codified as JLS v3 and is available since Java 5. (JSR
133 fixed in 2004)
That was badly needed (and I believe a similar fix was made in the CLR
2.0 memory model as well), but JRuby still targets Java 4, as does
nearly all of other Java code I’ve been asked to work on professionally
– there’s a bit of a gap between a JSR going in, and that Java version
being widely adopted.
(Admittedly, I may be behind the curve Java 5 adoption, and I’m less
sure about CLR 2.0 adoption as a whole.)
Anyway, for right now, this is a moot point in Ruby, since
double-checked locking isn’t possible to implement safely there; we have
neither volatile (broken or otherwise), nor anything like .NET’s
System.Threading.Thread.MemoryBarrier(). The only way to get the
required memory barriers in Ruby is to trust the library locking
primitives to provide them when they are needed. The safe thing is to
simply never to perform accesses to shared variables outside the
protection of a lock, since that being safe is the minimum guarantee any
locking implementation must provide.
-mental