Ruby中是否存在保证/记录为原子的任何操作/方法?

时间:2013-08-07 20:47:52

标签: ruby concurrency

我做了一个快速的谷歌搜索,几乎所有用Ruby编写的原子性建议都围绕操作包装Mutex。但是,我怀疑这种方法不能满足通常的原子性定义,因为信号可能会中断同步代码。例如(取自Ruby Best Practices):

lock = Mutex.new

# XXX this is an example of what NOT to do inside a signal handler:
trap(:USR1) do
  lock.synchronize do
    # if a second SIGUSR1 arrives here, this block of code
    # will fire again.   Attempting Mutex#synchronize twice
    # the same thread leads to a deadlock error
  end
end

我知道原子性对于高级语言来说并不那么重要,但是为了研究起见,我希望得到关于GIL实现的这个问题的规范性答案(例如 MRI 2.0.0 )没有例如 JRuby 1.7.4和Rubinius 1.2.4

1 个答案:

答案 0 :(得分:1)

我对这个主题知之甚少。但我会尽力回答。

Jesse Storimer写了一篇关于并发的文章。我强烈建议你阅读有关它的所有3个部分。

http://www.jstorimer.com/blogs/workingwithcode/8100871-nobody-understands-the-gil-part-2-implementation

第2部分的结论是GIL保证本机C方法实现是原子的。

你提供的例子实际上更多是重入问题然后是原子性。我不知道这是相同的事情还是它有多密切相关。

与文章说明一样,ruby不同于事件驱动编程,其中回调是同步的,这意味着如果你发送信号USR1两次,第二个处理程序将在第一个完成后执行。所以你不会两次锁定互斥锁。

但是在ruby中的信号处理是异步的。意思是如果你发送信号两次。第二个处理程序将中断第一个处理程序。因为第一个已经获得了锁,所以尝试获取相同锁的第二个处理程序将抛出异​​常。我相信这个问题不是特定于ruby的。

解决此问题的方法之一是创建一个队列来执行信号处理。另一个解决方案是使用一种称为“自管”技巧的方法。这两种方法。在这篇文章中再次讨论了令人敬畏的Jesse Storimer:

http://rubysource.com/the-self-pipe-trick-explained/

所以, 对于MRI 2.0.0,我相信仍然有GIL,所以ruby只保证原生C方法是原子的。

JRuby是JVM支持的所以我的猜测是所有的线程和锁定机制都是在JVM之上实现的

Rubinius 1.2还有GIL,所以我相信它和MRI一样。但是Rubinius 2.x移除了GIL。我对Rubinius没有多少经验,所以我不太确定。

要回答这个问题,如果您正在使用ruby中的多线程应用程序。互斥类应该保护该块一次只能由单个线程执行。