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

时间:2016-06-17 12:17:38

标签: ruby windows shell powershell spawn

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

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

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

p1.detach

据我所知,这应该创建一个独立于父级的新进程。我甚至使用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

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}"

我在调查过程中找到了win32-process宝石。它似乎是使用win32 API调用生成进程。有谁知道这个库是否能解决问题?

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:2)

我无法在Windows中找到任何进程组,除了将CTRL事件发送到Process Creation Flags MSDN docs中所述的多个进程:

  

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

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

  

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

From CreateProcess MSDN docs

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

  

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

From HandlerRoutine callback MSDN docs

创建流程时,SetConsoleCtrlHandler(NULL,TRUE)标记设置的CREATE_NEW_PROCESS_GROUP不会影响此事件的处理。

以上所有意味着CREATE_NEW_PROCESS_GROUP标志与您正在观察的行为无关。

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

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

  

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

From Creation of a Console MSDN docs

我相信Ruby的spawnwin32-process gem做的不同。我没有尝试调试两者,以便查看它们提供给CreateProcess的标志的具体差异,尽管这将是一件有趣的事情。

还有其他方法可以在不继承父级的控制台或IO句柄的情况下创建子进程。示例包括CREATE_NO_WINDOWCREATE_NEW_CONSOLE标记,Job Objects等。