Python/Windows/ctypes:调用 WaitForMultipleObjects 后如何获取进程返回状态?
Posted
技术标签:
【中文标题】Python/Windows/ctypes:调用 WaitForMultipleObjects 后如何获取进程返回状态?【英文标题】:Python/Windows/ctypes: How to get process return status after calling WaitForMultipleObjects? 【发布时间】:2012-04-25 08:19:46 【问题描述】:我和this guy有同样的用例,我真的很喜欢this answer,除了我有一个额外的要求:我需要从子进程中获取返回状态。
这是我修改他的程序的尝试。我是 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
权限,如果我注释掉GetExitCodeProcess()
调用,CloseHandle()
调用就可以正常工作。
有什么想法吗?等待一堆进程后如何获取状态码?
【问题讨论】:
【参考方案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”不是以某种方式损坏了吗?您尝试了其他命令吗?
【讨论】:
以上是关于Python/Windows/ctypes:调用 WaitForMultipleObjects 后如何获取进程返回状态?的主要内容,如果未能解决你的问题,请参考以下文章