2012-04-25 86 views
0

我有和this guy一样的用例,我真的很喜欢this answer,只是我有一个额外的要求:我需要从子进程获取返回状态。Python/Windows/ctypes:如何在调用WaitForMultipleObjects之后获取进程返回状态?

这是我尝试修改他的程序。我在Windows的土地和Python ctypes的游客,所以希望我没有做任何愚蠢的......

import ctypes, subprocess 
from random import randint 
import os 
SYNCHRONIZE=0x00100000 
PROCESS_QUERY_INFORMATION=0x0400 
INFINITE = -1 
numprocs = 5 
handles = {} 

class Err(BaseException): pass 

for i in xrange(numprocs): 
    sleeptime = randint(5,10) 
    p = subprocess.Popen([r"c:\MinGW\msys\1.0\bin\sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) 
    h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, p.pid) 
    handles[h] = p.pid 
    print "Spawned Process %d" % p.pid 

while len(handles) > 0: 
    print "Waiting for %d children..." % len(handles) 
    arrtype = ctypes.c_long * len(handles) 
    handle_array = arrtype(*handles.keys()) 
    ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE) 
    h = handle_array[ret] 
    print "Process %d done" % handles[h] 
    i = ctypes.c_int(0) 
    pi = ctypes.pointer(i) 
    if ctypes.windll.kernel32.GetExitCodeProcess(h, pi) == 0: 
    err = ctypes.windll.kernel32.GetLastError() 
     raise Err("GetExitCodeProcess: %d" % (err)) 
    print "Status code is: %d" % (i) 
    if ctypes.windll.kernel32.CloseHandle(h) == 0: 
    err = ctypes.windll.kernel32.GetLastError() 
    raise Err("CloseHandle: %d" % (err)) 
    del handles[h] 
print "All done! 

但是当我运行它,我得到一个错误:

Traceback (most recent call last): 
    File "test.py", line 30, in <module> 
    raise Err("GetExitCodeProcess: %d" % (err)) 
__main__.Err: GetExitCodeProcess: 6 

看来,error 6 is ERROR_INVALID_HANDLE。但我不知道为什么这个句柄是无效的;我要求PROCESS_QUERY_INFORMATION权限和CloseHandle()通话正常工作,如果我注释掉GetExitCodeProcess()通话。

任何想法?如何在等待一堆进程之后获取状态码?

回答

1

使用这个确切的Python代码(和你的一样只是一些缩进固定和路径的Sleep.exe删除):

import ctypes, subprocess 
from random import randint 
import os 
SYNCHRONIZE=0x00100000 
PROCESS_QUERY_INFORMATION=0x0400 
INFINITE = -1 
numprocs = 5 
handles = {} 

class Err(BaseException): pass 

for i in xrange(numprocs): 
    sleeptime = randint(5,10) 
    p = subprocess.Popen([r"sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) 
    h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, p.pid) 
    handles[h] = p.pid 
    print "Spawned Process %d" % p.pid 

while len(handles) > 0: 
    print "Waiting for %d children..." % len(handles) 
    arrtype = ctypes.c_long * len(handles) 
    handle_array = arrtype(*handles.keys()) 
    ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE) 
    h = handle_array[ret] 
    print "Process %d done" % handles[h] 
    i = ctypes.c_int(0) 
    pi = ctypes.pointer(i) 
    if ctypes.windll.kernel32.GetExitCodeProcess(h, pi) == 0: 
     err = ctypes.windll.kernel32.GetLastError() 
     raise Err("GetExitCodeProcess: %d" % (err)) 
    print "Status code is: %d" % i.value 
    if ctypes.windll.kernel32.CloseHandle(h) == 0: 
     err = ctypes.windll.kernel32.GetLastError() 
     raise Err("CloseHandle: %d" % (err)) 
    del handles[h] 

print "All done!" 

给了我这样的输出:

C:\tmp\pyt>python -V 
Python 2.7.3 

C:\tmp\pyt>python a.py 
Spawned Process 4368 
Spawned Process 268 
Spawned Process 5792 
Spawned Process 4744 
Spawned Process 4484 
Waiting for 5 children... 
Process 5792 done 
Status code is: 0 
Waiting for 4 children... 
Process 4484 done 
Status code is: 0 
Waiting for 3 children... 
Process 268 done 
Status code is: 0 
Waiting for 2 children... 
Process 4368 done 
Status code is: 0 
Waiting for 1 children... 
Process 4744 done 
Status code is: 0 
All done! 

所以它似乎正在工作。其他地方不是你的问题吗?你使用的操作系统是什么(我的是Vista)?你有最新版本的Python(2.7.3)吗?不是你的“sleep.exe”破坏了吗?你尝试了另一个命令吗?

相关问题