Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronized Method for concurrency in Ruby [duplicate]

Tags:

ruby

Possible Duplicate:
Does ruby have the Java equivalent of synchronize keyword?

In Java we can make a method 'synchronized' by just using the 'synchronized' keyword in the function definition.

How do we do it in Ruby?

like image 535
Imran Omar Bukhsh Avatar asked Dec 30 '12 12:12

Imran Omar Bukhsh


People also ask

Is synchronized method more efficient?

If you synchronize a code block within that method then more than one thread can execute the method simultaneously, but only one thread can enter the synchronized block at a time. From this we can conclude that synchronizing on the smallest possible code block required is the most efficient way to do it.

What is synchronized in concurrency?

The word synchronization generally means sharing data between multiple processors or threads, while concurrency refers to a measure of– or the art of improving– how effectively an application allows multiple jobs required by that application (e.g. serving web page requests from a web server) to run simultaneously.

Can two synchronized methods in same class?

Yes, they can run simultaneously both threads. If you create 2 objects of the class as each object contains only one lock and every synchronized method requires lock.

Is synchronized block more efficient than synchronized method?

A Java synchronized block doesn't allow more than one JVM, to provide access control to a shared resource. The system performance may degrade because of the slower working of synchronized keyword. Java synchronized block is more efficient than Java synchronized method.


1 Answers

Synchronize keyword is not present in Ruby. Alternatively just can just wrap the method call to Mutex (i.e. fancy word for Lock).

Create new shared Mutex for that class (everyone must use the same Mutex (lock) to access the same variables):

NUM_THREADS = 4

class Foo
  def initialize
    @my_mutex = Mutex.new
    @my_val = 0 # should be private
  end

  def synchronize(&block)
    # to see what it does without the mutex in this example:
    # 1) comment this line
    @my_mutex.synchronize(&block)
    # 2) uncomment this line
    # yield
  end

  def current_value
    synchronize do
      @my_val
    end
  end

  def modify
    # the value should be 0 before and 0 after, if the Mutex is used correctly
    synchronize do
      @my_val += 1
      sleep 0.25
      @my_val -= 1
      sleep 0.25
    end
  end
end

foo = Foo.new

threads = []

# spawn N threads, all trying to change the value
threads += (1..NUM_THREADS).map { |i|
  Thread.new {
    puts "thread [##{i}]: modifying"
    foo.modify
  }
}

# spawn checking thread
threads << Thread.new {
  # print the value twice as fast as the other threads are changing it, so we are more likely to stumble upon wrong state
  (NUM_THREADS * 2).times {
    puts "thread [check]: checking..."
    raise if foo.current_value != 0 # locking failed, crash
    sleep 0.25
  }
}

threads.map { |t| t.join } # wait for all threads

puts "even though it took a while longer, it didn't crash, everyone is happy, managers didn't fire me... it worked!"

See http://apidock.com/ruby/Mutex

The program runs longer, because of all those locking. Speed depends on your ruby implementation (e.g. green threads, native threads..) and number of cores. If you disable mutex in this example above, the program crashes right away, because of the raise guard in checking thread. Note that the checking thread must use the mutex too, because otherwise it would still be able to read the value in the middle of change by other threads. I.e. everyone must use the same mutex to access that variable.

To make around the lack of synchronized keyword, I defined method synchronize which uses the class defined Mutex.

like image 63
Dalibor Filus Avatar answered Oct 12 '22 08:10

Dalibor Filus