Forum: Ruby-core [CommonRuby - Feature #8961][Open] Synchronizable module to easily wrap methods in a mutex

0373a8c7849a794ddc771f1bc9d9de13?d=identicon&s=25 tobiassvn (Tobias Svensson) (Guest)
on 2013-09-27 13:24
(Received via mailing list)
Issue #8961 has been reported by tobiassvn (Tobias Svensson).

----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from 'def'.

The Mixin adds a new 'synchronized' class method which would alias the
referenced method and redefines the original method wrapped in a
'synchronize do .. end' block.

This is probably somewhat related and an alternative to #8556.

--

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

require 'monitor'

module Synchronizable
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        monitor.synchronize do
          __send__(aliased, *args, &block)
        end
      end
    end
  end

  def monitor
    @monitor ||= Monitor.new
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include Synchronizable

  synchronized def bar
    # ...
  end
end
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2013-09-27 13:41
(Received via mailing list)
Issue #8961 has been updated by headius (Charles Nutter).


I would like to see this in 2.1, as a standard Module method. The fact
that "def" returns the method name now makes this really easy.

I think this would need to be implemented natively to work, however. The
prototype above has a key flaw: there's no guarantee that only one
Monitor will be created, so two threads could execute the same method at
the same time, synchronizing against different monitors. Putting the
synchronized wrapper into C code would prevent a potential context
switch when first creating the Monitor instance (or it could simply use
some other mechanism, such as normal Object monitor synchronization in
JRuby).

This feature is similar to an extension in JRuby called
JRuby::Synchronized that causes all method lookups to return
synchronized equivalents.

Combined with https://bugs.ruby-lang.org/issues/8556 this could go a
very long way toward giving Ruby users better tools to write thread-safe
code.
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42047

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from 'def'.

The Mixin adds a new 'synchronized' class method which would alias the
referenced method and redefines the original method wrapped in a
'synchronize do .. end' block.

This is probably somewhat related and an alternative to #8556.

--

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

require 'monitor'

module Synchronizable
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        monitor.synchronize do
          __send__(aliased, *args, &block)
        end
      end
    end
  end

  def monitor
    @monitor ||= Monitor.new
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include Synchronizable

  synchronized def bar
    # ...
  end
end
C4e88907313843cf07f6d85ba8162120?d=identicon&s=25 tobiassvn (Tobias Svensson) (Guest)
on 2013-09-27 14:45
(Received via mailing list)
Issue #8961 has been updated by tobiassvn (Tobias Svensson).


Having this as a method on Module directly would of course be ideal.
However, I believe the mutex/monitor used should still be exposed as a
private method so it can be used without the 'synchronized' method.
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42049

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from 'def'.

The Mixin adds a new 'synchronized' class method which would alias the
referenced method and redefines the original method wrapped in a
'synchronize do .. end' block.

This is probably somewhat related and an alternative to #8556.

--

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

require 'monitor'

module Synchronizable
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        monitor.synchronize do
          __send__(aliased, *args, &block)
        end
      end
    end
  end

  def monitor
    @monitor ||= Monitor.new
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include Synchronizable

  synchronized def bar
    # ...
  end
end
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2013-09-27 20:45
(Received via mailing list)
Issue #8961 has been updated by headius (Charles Nutter).


tobiassvn (Tobias Svensson) wrote:
> Having this as a method on Module directly would of course be ideal. However, I
believe the mutex/monitor used should still be exposed as a private method so it
can be used without the 'synchronized' method.

Maybe. I don't like the idea of exposing this mutex/monitor, since it
could be modified or locked and never released. I would be more in favor
of a "tap" form that synchronizes against the same internal monitor,
similar to Java's "synchronized" keyword.

  obj.synchronized { thread-sensitive code here }

That would also open up the possibility of using a lighter-weight
internal mutex/monitor rather than the rather heavy-weight Ruby-land
version.
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42057

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from 'def'.

The Mixin adds a new 'synchronized' class method which would alias the
referenced method and redefines the original method wrapped in a
'synchronize do .. end' block.

This is probably somewhat related and an alternative to #8556.

--

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

require 'monitor'

module Synchronizable
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        monitor.synchronize do
          __send__(aliased, *args, &block)
        end
      end
    end
  end

  def monitor
    @monitor ||= Monitor.new
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include Synchronizable

  synchronized def bar
    # ...
  end
end
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 Nobuyoshi Nakada (nobu)
on 2013-09-28 02:24
(Received via mailing list)
Issue #8961 has been updated by nobu (Nobuyoshi Nakada).


headius (Charles Nutter) wrote:
> Maybe. I don't like the idea of exposing this mutex/monitor, since it could be
modified or locked and never released. I would be more in favor of a "tap" form
that synchronizes against the same internal monitor, similar to Java's
"synchronized" keyword.
>
>   obj.synchronized { thread-sensitive code here }

Use MonitorMixin.

----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42061

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from 'def'.

The Mixin adds a new 'synchronized' class method which would alias the
referenced method and redefines the original method wrapped in a
'synchronize do .. end' block.

This is probably somewhat related and an alternative to #8556.

--

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

require 'monitor'

module Synchronizable
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        monitor.synchronize do
          __send__(aliased, *args, &block)
        end
      end
    end
  end

  def monitor
    @monitor ||= Monitor.new
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include Synchronizable

  synchronized def bar
    # ...
  end
end
F1d6cc2b735bfd82c8773172da2aeab9?d=identicon&s=25 Nobuyoshi Nakada (nobu)
on 2013-10-01 07:15
(Received via mailing list)
Issue #8961 has been updated by nobu (Nobuyoshi Nakada).

Description updated


----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42134

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


=begin
I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from
'(({def}))'.

The Mixin adds a new '(({synchronized}))' class method which would alias
the referenced method and redefines the original method wrapped in a
'(({synchronize do .. end}))' block.

This is probably somewhat related and an alternative to #8556.

---

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

  require 'monitor'

  module Synchronizable
    module ClassMethods
      def synchronized(method)
        aliased = :"#{method}_without_synchronization"
        alias_method aliased, method

        define_method method do |*args, &block|
          monitor.synchronize do
            __send__(aliased, *args, &block)
          end
        end
      end
    end

    def monitor
      @monitor ||= Monitor.new
    end

    def self.included(base)
      base.extend(ClassMethods)
    end
  end

  class Foo
    include Synchronizable

    synchronized def bar
      # ...
    end
  end
=end
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2013-10-01 19:13
(Received via mailing list)
Issue #8961 has been updated by headius (Charles Nutter).


nobu (Nobuyoshi Nakada) wrote:
> headius (Charles Nutter) wrote:
> > Maybe. I don't like the idea of exposing this mutex/monitor, since it could be
modified or locked and never released. I would be more in favor of a "tap" form
that synchronizes against the same internal monitor, similar to Java's
"synchronized" keyword.
> >
> >   obj.synchronized { thread-sensitive code here }
>
> Use MonitorMixin.

Yeah, that's not a bad option from a pure-Ruby perspective. We could add
"synchronized" to classes that include MonitorMixin, perhaps?

* added to monitor.rb:

module MonitorMixin
  module ClassMethods
    def synchronized(method)
      aliased = :"#{method}_without_synchronization"
      alias_method aliased, method

      define_method method do |*args, &block|
        mon_enter
        begin
          __send__(aliased, *args, &block)
        ensure
          mon_exit
        end
      end
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

class Foo
  include MonitorMixin

  synchronized def bar
    # ...
  end
end

...

My suggestion to have it be native on Module opened up the possibility
of implementing it in a faster, native way. MonitorMixin has a very
large perf hit on all impls right now, but especially MRI. See my
benchmarks in
https://github.com/ruby/ruby/pull/405#issuecomment-25417666
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42170

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


=begin
I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from
'(({def}))'.

The Mixin adds a new '(({synchronized}))' class method which would alias
the referenced method and redefines the original method wrapped in a
'(({synchronize do .. end}))' block.

This is probably somewhat related and an alternative to #8556.

---

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

  require 'monitor'

  module Synchronizable
    module ClassMethods
      def synchronized(method)
        aliased = :"#{method}_without_synchronization"
        alias_method aliased, method

        define_method method do |*args, &block|
          monitor.synchronize do
            __send__(aliased, *args, &block)
          end
        end
      end
    end

    def monitor
      @monitor ||= Monitor.new
    end

    def self.included(base)
      base.extend(ClassMethods)
    end
  end

  class Foo
    include Synchronizable

    synchronized def bar
      # ...
    end
  end
=end
C4e88907313843cf07f6d85ba8162120?d=identicon&s=25 tobiassvn (Tobias Svensson) (Guest)
on 2013-10-02 15:15
(Received via mailing list)
Issue #8961 has been updated by tobiassvn (Tobias Svensson).


I suppose if this is being added to MonitorMixin it should probably be
in Mutex_m as well?
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42214

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


=begin
I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from
'(({def}))'.

The Mixin adds a new '(({synchronized}))' class method which would alias
the referenced method and redefines the original method wrapped in a
'(({synchronize do .. end}))' block.

This is probably somewhat related and an alternative to #8556.

---

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

  require 'monitor'

  module Synchronizable
    module ClassMethods
      def synchronized(method)
        aliased = :"#{method}_without_synchronization"
        alias_method aliased, method

        define_method method do |*args, &block|
          monitor.synchronize do
            __send__(aliased, *args, &block)
          end
        end
      end
    end

    def monitor
      @monitor ||= Monitor.new
    end

    def self.included(base)
      base.extend(ClassMethods)
    end
  end

  class Foo
    include Synchronizable

    synchronized def bar
      # ...
    end
  end
=end
F1d37642fdaa1662ff46e4c65731e9ab?d=identicon&s=25 Charles Nutter (headius)
on 2013-10-02 23:52
(Received via mailing list)
Issue #8961 has been updated by headius (Charles Nutter).


tobiassvn (Tobias Svensson) wrote:
> I suppose if this is being added to MonitorMixin it should probably be in
Mutex_m as well?

I don't think so, since a Mutex is not reentrant and what we want is
monitor semantics for #synchronized.
----------------------------------------
Feature #8961: Synchronizable module to easily wrap methods in a mutex
https://bugs.ruby-lang.org/issues/8961#change-42233

Author: tobiassvn (Tobias Svensson)
Status: Open
Priority: Normal
Assignee:
Category:
Target version:


=begin
I propose a Synchronizable mixin to easily wrap methods in a mutex which
works together with Ruby 2.1's method name symbols returned from
'(({def}))'.

The Mixin adds a new '(({synchronized}))' class method which would alias
the referenced method and redefines the original method wrapped in a
'(({synchronize do .. end}))' block.

This is probably somewhat related and an alternative to #8556.

---

Proof of concept (I've used Monitor here so potential users won't have
to worry about reentrancy):

  require 'monitor'

  module Synchronizable
    module ClassMethods
      def synchronized(method)
        aliased = :"#{method}_without_synchronization"
        alias_method aliased, method

        define_method method do |*args, &block|
          monitor.synchronize do
            __send__(aliased, *args, &block)
          end
        end
      end
    end

    def monitor
      @monitor ||= Monitor.new
    end

    def self.included(base)
      base.extend(ClassMethods)
    end
  end

  class Foo
    include Synchronizable

    synchronized def bar
      # ...
    end
  end
=end
This topic is locked and can not be replied to.