当shell终止时,Windows上生成的Ruby进程将死亡

Har*_*rdy 6 ruby windows shell powershell spawn

我试图在Windows上使用以下内容生成Ruby进程:

p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"],  :new_pgroup => true)
Run Code Online (Sandbox Code Playgroud)

然后我也通过以下方式脱离了这个过程:

p1.detach
Run Code Online (Sandbox Code Playgroud)

到目前为止,我应该理解创建一个独立于父进程的新进程.我甚至使用new_pgroup参数来确保新进程获得自己的进程组.

当我执行我的脚本时,子进程启动并继续运行.产生子进程的脚本的执行也完成了.但是,当我现在关闭shell时,子进程就会死掉.我希望它能继续运行(它在OS X和Linux上运行).我无法弄清楚这是否是Windows上Ruby运行时的错误,或者这是否是Windows的限制以及它如何处理进程.

为了完整性,我想要做的完整Ruby代码:


spawner.rb:可以通过执行ruby spawner.rb并生成一个新的子流程.进程创建的是loop.rb,这只是一个无限循环.根据操作系统,它为进程组创建指定了不同的参数.

require "tempfile"
require 'rbconfig'

class SpawnTest

  def self.spawn_process

    if os == :windows
      p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"],  :new_pgroup => true)
    else
      p1 = spawn('ruby', 'loop.rb', [:out, :err] => ['process.log', "w"],  :pgroup => true)
    end

    # Detach from the processes so they will keep running
    puts p1
    Process.detach(p1)
  end

  def self.os
    @os ||= (
    host_os = RbConfig::CONFIG['host_os']
    case host_os
      when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
        :windows
      when /darwin|mac os/
        :macosx
      when /linux/
        :linux
      when /solaris|bsd/
        :unix
      else
        raise Error::WebDriverError, "unknown os: #{host_os.inspect}"
    end
    )
  end
end

if __FILE__ == $0
  SpawnTest.spawn_process
end
Run Code Online (Sandbox Code Playgroud)

loop.rb

$stdout.sync = true
$stderr.sync = true

i = 0
while i < 10000
  $stdout.puts "Iteration #{i}"
  sleep 1
  i = i + 1
end

$stdout.puts "Bye from #{Process.pid}"
Run Code Online (Sandbox Code Playgroud)

我在调查期间找到了win32-process gem.它似乎是使用win32 API调用生成进程.有谁知道这个库是否能解决这个问题?

任何帮助赞赏.

Nic*_*lov 4

除了将事件分派到多个进程之外,我在 Windows 中找不到进程组的任何用途,如进程创建标志 MSDN 文档CTRL中所述:

GenerateConsoleCtrlEvent 函数使用进程组来向一组控制台进程发送 CTRL+BREAK 信号。

CREATE_NEW_PROCESS_GROUP指定标志时实际发生的情况是......

...代表新进程隐式调用 SetConsoleCtrlHandler(NULL,TRUE);这意味着新进程已禁用 CTRL+C。这让 shell 自己处理 CTRL+C,并有选择地将该信号传递给子进程。CTRL+BREAK 未禁用,可用于中断进程/进程组。

来自 CreateProcess MSDN 文档

请注意,这与使用按钮关闭控制台窗口不同x。在后一种情况下,进程接收到CTRL_CLOSE_EVENT

当用户关闭控制台(通过单击控制台窗口的窗口菜单上的“关闭”,或单击任务管理器中的“结束任务”按钮命令)时,系统向附加到控制台的所有进程发送的信号。

来自 HandlerRoutine 回调 MSDN 文档

该事件的处理不受创建进程时标志SetConsoleCtrlHandler(NULL,TRUE)设置的影响。CREATE_NEW_PROCESS_GROUP

以上所有内容都意味着CREATE_NEW_PROCESS_GROUPflag 与您所观察到的行为无关。

默认情况下,子进程继承父进程的控制台窗口和 IO 句柄。因此,当您通过单击按钮关闭 shell 时x,它会收到CTRL_CLOSE_EVENT并且没有不终止的选项。

为了避免这种情况,子进程不应附加到父控制台。这是通过DETACHED_PROCESS向 Windows API 提供标志来完成的CreateProcess

默认情况下,控制台进程继承其父级的控制台...如果控制台进程是使用带有DETACHED_PROCESS 的CreateProcess 创建的,则控制台进程不会附加到控制台。

来自创建控制台 MSDN 文档

我认为这就是 Rubyspawnwin32-processgem 的不同之处。我没有尝试调试两者来查看它们提供的标志的具体差异,CreateProcess尽管这将是一件有趣的事情。

还有其他方法可以创建子进程而不继承父进程的控制台或 IO 句柄。示例有CREATE_NO_WINDOWCREATE_NEW_CONSOLE标志、作业对象等。