Ruby 如何托管子进程

dreamskyvt · 2013年01月25日 · 最后由 skandhas 回复于 2013年01月29日 · 4375 次阅读

在父进程中,开启一个子进程,如何在不影响子进程的情况下,将父进程关闭掉

父进程退出结束是不会结束子进程的。

#1 楼 @lgn21st 你好,能举个例子么,是用什么命令实现的。我有试过 system("cmd"), exec("cmd"), 和 cmd, 都无法做到父进程先于子进程结束,必须等待子进程完成后才退出

fork { sleep 1; puts "hi" }

很感谢你的帮助,但是我需要在 windows 上执行,悲剧啊。。。

我有个想法,在子进程里把父进程的 kill 了,不知道行不行,马上试一试

@lgn21st 应该说只有 windows 的子进程不受父进程影响...

但是 system, exec 都是等待子进程完成才结束的

创建独立进程可以用 win32-process http://rubydoc.info/gems/win32-process/0.7.1/frames

1.9 用 Process.spawn http://rubydoc.info/stdlib/core/Process.spawn

#5 楼 @luikore 我现在需要用 ruby 写一个公用的脚本,环境方面越简单越好,要求所有人都安装 ruby 已经挺勉强了,还要增加 gem 就更难了。 脚本功能很简单,功能方面打个比方吧:双击后在命令行打印一些信息,提示用户脚本已经启动了,之后打开其他的应用,也就是所谓的子进程。想要解决的问题是,子进程打开后,怎么吧提示信息的窗口给关闭了,或者可以动态的转为后台运行也成

#6 楼 @dreamskyvt 知道为什么 windows 叫 windows 么?就是因为程序都必须有一个窗口... 所谓后台程序只是把窗口隐藏了而已... 你可以用 win32api GetConsoleWindow() 获得控制台窗口句柄,然后用 ShowWindow(hwnd, SW_HIDE) 把它隐藏了...


用户懒得装 gem 有各种绕过去的办法,例如你可以在脚本里

begin
  require '...'
rescue LoadError
  system "gem install ..."
end

或者用 OCRA 把 ruby 和 gem 和脚本打包成一个可执行文件 (以前室友给游戏汉化组做的打包工具就是这么干的...), 或者你可以写一个 msi installer 在里面拷文件,各种奇技淫巧都有...

#7 楼 @luikore 非常感谢 时间关系,要回家了,晚点再试试窗口的隐藏。 你说的第二点用脚本来装 gem 也是正道,居然忘了这戳。。

#2 楼 @dreamskyvt 例子

fork do
  5.times do
    sleep 1
    puts "I'm an orphan!"
  end
end

abort "Parent process died..."

不过我没有 windows 上的进程相关的知识,经验。估计 cygwin 也不符合你的需求。还是拜一下 @luikore 大神,他的方案看起来非常靠谱。

#9 楼 @lgn21st 原来是这样... 经常 kill 就连同子进程一起消灭了,我就想当然的以为父进程里能退子进程... 但其实 kill 是给整个进程组发的信号,exit / abort 只退出当前进程

windows 里进程没有树形关系,进程组好像就是个摆设,能处理的信号太少... 但是创建进程的 api CreateProcess 却又巨复杂,学起来极其浪费人参...

#11 楼 @luikore 学起来极其浪费人参 特别浪费西洋参 :-)

Process.setsid

在 windows 下 用 Process.spawn 就 OK。 Windows 下的进程之间的关系相对 Unix 要简单的多啦:)

puts 'Notepad start...'
Process.spawn 'notepad.exe'

这个脚本在 windows 下,ruby 进程在创建完 notepad 进程后就结束,也不会影响到 notepad 进程。完全满足你的需要。

#15 楼 @skandhas 赞啊,使用真的非常简单,唯一不足的是需要 ruby1.9

#16 楼 @dreamskyvt 其实 @luikore 在 5 楼已经提到了 Process.spawn. ;)

如果你是使用 Ruby 1.8,而且又不想安装其他 gem 的话,你可以直接用 Win32API 来调用 WinExec 来完成类似的工作。当然,CreateProcess 也可以,但是参数啰嗦,WinExec 只有 2 个参数。

require "Win32API"

WinExec = Win32API.new('kernel32.dll', 'WinExec', 'PI', 'I')
WinExec.call 'notepad.exe', 1

我的测试环境是:WinXP,Ruby 1.8.6, Ruby 1.8.7, Ruby 1.9 都可以运行。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号