Ruby中的同步方法用于并发处理

20

抱歉,我的问题与以上评论中的链接相似。请随意关闭此问题。 - Imran Omar Bukhsh
我不会投票关闭。这个答案更好。 - Ismael
1个回答

22

在 Ruby 中没有同步关键字。相反,可以将方法调用包装到 Mutex(即锁的花哨说法)中。

为该类创建新的共享 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实现(例如绿色线程、本机线程等)和核心数量。如果在上面的示例中禁用mutex,则程序会立即崩溃,因为检查线程中的raise guard。请注意,检查线程也必须使用mutex,否则它仍然可以在其他线程更改变量的过程中读取该值。即每个人都必须使用相同的mutex来访问该变量。
为了弥补缺乏synchronized关键字的不足,我定义了一个方法synchronize,它使用类定义的Mutex

这个怎么样?https://dev59.com/dnA75IYBdhLWcg3wlqSh? - Imran Omar Bukhsh
13
第一个代码示例不错,但Mutex.new.synchronize是无用的。因为你没有保留对新创建的Mutex的引用,所以没有其他线程可以尝试锁定它,因此它将永远不会从关键区域中排除任何线程(这正是互斥锁的全部目的)。 - Alex D
嗯...我只是注释掉了@my_mutex.synchronize do,答案还是一样的 - 0。所以这并不是非常清晰的答案。主要是代码执行的顺序。 - skywinder
如果我注释掉同步块,结果可能会混乱。不过这可能取决于你使用的 Ruby 运行时。每个运行时都以不同的方式处理线程。在所有运行时上,结果应该是相当随机和不一致的。尝试多次运行它。 - Dalibor Filus
你使用了哪个运行时?我得到的结果和@skywinder一样。我甚至添加了一个睡眠时间,在将my_value复制到临时变量并使用它之间。 - Bren
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接