5

在 MRI Ruby 中,我可以这样做:

def transfer
  internal_server = self.init_server
  pid = fork do
    internal_server.run
  end

  # Make the server process run independently.
  Process.detach(pid)

  internal_client = self.init_client
  # Do other stuff with connecting to internal_server...
  internal_client.post('some data')    
ensure
  # Kill server
  Process.kill('KILL', pid) if pid
end

但是上面的代码不会在 jRuby 中运行,因为它不支持 'fork' 方法:

NotImplementedError: fork is not available on this platform

在 jRuby 中是否有任何替代解决方案?

谢谢。

4

2 回答 2

7

这是一个很好的问题,但不幸的是,如果你想要的是启动一个与父进程共享状态的新进程,我不相信 JVM 可以安全地给你想要的东西。那是因为分叉只复制当前正在运行的线程。例如,GC 线程不会被复制。您不想在没有 GC 的情况下运行 JVM。

使用 fork 的唯一半安全方式是之后立即执行。

Charles Nutter 在他的博客上首先说您可以使用 FFI 来分叉和执行,但随后提出了一个警告:

以这种方式使用 fork+exec 的最大问题是,您不能保证在 fork 调用和 exec 调用之间*没有发生*。例如,如果 JVM 决定 GC 或移动内存,您可能会在 JVM 进程级别发生致命崩溃。因此,我不建议在 JRuby 中通过 FFI 使用 fork + exec,尽管它非常酷。

我倾向于相信他的建议。

因此,fork 和 exec 会带来一些风险,但保留分叉的 JVM 是自找麻烦。

您应该认真考虑 Sergio 的评论建议的替代方案。

于 2012-11-09T23:39:04.350 回答
1

我找到了解决方案。我们可以使用 JRuby 中的内置库 FFI 来“模拟”MRI 中的 Process.fork。

# To mimic the Process.fork in MRI Ruby
module JRubyProcess
  require 'ffi'
  extend FFI::Library
  ffi_lib FFI::Library::LIBC
  attach_function :fork, [], :int
end

pid = JRubyProcess.fork do
  #internal_server.run
end

更多细节:

https://github.com/ffi/ffi

http://blog.headius.com/2008/10/ffi-for-ruby-now-available.html

于 2012-09-12T03:01:25.177 回答