Windowsでプロセスグループを指定して spawn する方法
Linux で プロセスグループを指定して spawn を実行する場合は pgroup
を指定しますが、Windowsではこのオプションはサポートされていません。Windowsでプロセスグループを作成するには new_pgroup
を指定します。ただし、spawnの記述を間違うとshell経由でプロセスが起動してしまうため、このオプションが機能しなくなるため注意が必要です。
Ruby プログラム(間違い)
spawnの第一引数にコマンドライン引数も含めて渡してしまうとshell経由での起動となるため、Ctrl-Cがshellに伝わってしまってshellごと子プロセスが終了する。
a.rb
spawn "ruby b.rb", new_pgroup: true loop do print "test\n" sleep(1) rescue Interrupt exit(false) end
b.rb
loop do print "#{Time.now}\n" sleep(1) end
Ruby プログラム(shellを経由しない場合)
spawnにコマンドと引数を分けて渡してやると、shellを経由しなくなる。複数の引数を渡したい場合は、それぞれを分けて渡すこと。
a.rb
spawn "ruby", "b.rb", new_pgroup: true loop do print "test\n" sleep(1) rescue Interrupt exit(false) end
調査用 Go プログラム (参考)
// +build ignore package main import ( "fmt" "os/exec" "syscall" "time" ) const ( CREATE_NEW_PROCESS_GROUP = 0x00000200 ) func main() { var cmd *exec.Cmd cmd = exec.Command("ruby", "-e", "'sleep'") cmd.SysProcAttr = &syscall.SysProcAttr{ CreationFlags: CREATE_NEW_PROCESS_GROUP, } cmd.Start() time.Sleep(1 * time.Second) fmt.Println(cmd.Process.Pid) for { time.Sleep(1 * time.Second) } }
調査用 C言語 プログラム (参考)
#include <stdio.h> #include <Windows.h> #include <string.h> #include <wchar.h> void main() { BOOL fRet; STARTUPINFO aStartupInfo; PROCESS_INFORMATION aProcessInformation; SECURITY_ATTRIBUTES sa; DWORD dwCreationFlags; const WCHAR* prog = NULL; WCHAR cmd[] = L"ruby C:\\dev\\ruby\\test_spawn\\b.rb"; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; memset(&aStartupInfo, 0, sizeof(aStartupInfo)); memset(&aProcessInformation, 0, sizeof(aProcessInformation)); aStartupInfo.cb = sizeof(aStartupInfo); aStartupInfo.dwFlags = STARTF_USESTDHANDLES; aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP; printf("start\n"); fRet = CreateProcess(prog, cmd, &sa, &sa, sa.bInheritHandle, dwCreationFlags, NULL, NULL, &aStartupInfo, &aProcessInformation); printf("fRet: %d\n", fRet); CloseHandle(aProcessInformation.hThread); printf("PID: %d\n", aProcessInformation.dwProcessId); WaitForSingleObject(aProcessInformation.hProcess, INFINITE); printf("end \n"); }