Java では、関数定義で 'synchronized' キーワードを使用するだけで、メソッドを 'synchronized' にすることができます。
Ruby でそれを行うにはどうすればよいでしょうか。
Java では、関数定義で 'synchronized' キーワードを使用するだけで、メソッドを 'synchronized' にすることができます。
Ruby でそれを行うにはどうすればよいでしょうか。
Synchronize キーワードは Ruby にはありません。あるいは、単にメソッド呼び出しをラップすることもできますMutex
(つまり、Lock の派手な言葉)。
そのクラスの新しい共有 Mutex を作成します (全員が同じ変数にアクセスするには、同じ Mutex (ロック) を使用する必要があります)。
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!"
http://apidock.com/ruby/Mutexを参照
これらすべてのロックにより、プログラムの実行時間が長くなります。速度は、Ruby の実装 (グリーン スレッド、ネイティブ スレッドなど) とコア数によって異なります。上記の例でミューテックスを無効にすると、スレッドのチェックで保護が発生するため、プログラムはすぐにクラッシュします。チェックスレッドもミューテックスを使用する必要があることに注意してください。そうしないと、他のスレッドによる変更の途中で値を読み取ることができるためです。つまり、全員が同じミューテックスを使用してその変数にアクセスする必要があります。
synchronized
キーワードの不足を回避するためにsynchronize
、クラス defined を使用するメソッドを定義しMutex
ました。