Description
Hello,
I would like to build a common synchronization layer in concurrent-ruby
having following API:
def Concurrent.lock(object); end #reentrant
def Concurrent.try_lock(object); end
def Concurrent.unlock(object); end
def Concurrent.synchronize(object, &block); end
def Concurrent.wait(object, timeout = nil); end # as Java Object#wait
def Concurrent.signal(object); end # as Java Object#notify
def Concurrent.broadcast(object); end # as Java Object#notifyAll
Which would have different implementation based on Ruby interpreter.
I kindly ask @brixen @headius @hone @ko1 @yorickpeterse @zzak to help with finding the best options for the different implementations. This PR is intended to serve to discus the options and issues, I'll open PR with implementation later to discuss details based on what is figured out here.
Proposed implementations
MRI
Injecting Monitor to an object, something like:
require 'monitor'
INJECTION_BARRIER = Mutex.new
def synchronize(object)
get_mutex(object).synchronize { yield }
end
def lock(object)
get_mutex(object).enter
end
def unlock(object)
get_mutex(object).exit
end
def get_mutex(object)
object.instance_variable_get(:@__monitor__) or INJECTION_BARRIER.synchronize do
object.instance_variable_get(:@__monitor__) or
object.instance_variable_set(:@__monitor__, Monitor.new)
end
end
Similarly a ConditionVariable
would be injected to support wait
, signal
, broadcast
.
JRuby
Delegate to methods on JRuby
module, see this PR jruby/jruby#2594.
It uses wait
, notify
, notifyAll
methods on Java object to implement wait
, signal
, broadcast
. synchronize
runs a Block
wrapped in synchronized
Java keyword. lock
, unlock
, try_lock
are using methods monitorEnter
, monitorExit
, tryMonitorEnter
on sun.misc.Unsafe
.
Rubinius
Implement lock
, unlock
, try_lock
and synchronize
by delegation to same methods on Rubinius
module. wait
, signal
, broadcast
would be supported by injecting ConditionalVariable
into object's instance variable (when locked).