我一直在尝试编写一个应用程序,它运行子流程,并且(除其他外)在gui中显示它们的输出,并允许用户单击按钮取消它们。我开始这样的过程:
queue = Queue.Queue(500)
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
iothread = threading.Thread(
target=simple_io_thread,
args=(process.stdout, queue))
iothread.daemon=True
iothread.start()
简单线程定义如下:
def simple_io_thread(pipe, queue):
while True:
line = pipe.readline()
queue.put(line, block=True)
if line=="":
break
这很管用。在我的UI中,我定期从队列中执行非阻塞“get”但是,当我想终止子流程时,问题就来了(子进程是一个任意进程,不是我自己写的东西。)我可以使用terminate方法终止进程,但我不知道如何保证我的I/O线程将终止它通常会阻塞管道上的I/O在我终止进程之后,这可能会结束,也可能不会结束。(如果子进程生成了另一个子进程,我可以杀死第一个子进程,但第二个子进程仍将保持管道打开我甚至不知道如何让这样的孙子干净地终止。)之后,I/O线程将尝试将输出排队,但我不想无限期地承诺从队列中读取。
理想情况下,我希望有一些方法来请求子进程的终止,阻塞一段时间(解决方案使用I/O线程对我来说并不重要如果有其他方法可以在Windows和Linux上使用Python2.6和Tkinter图形用户界面,那就没问题了。
EDIT-Will's answer和我在web上看到的关于用其他语言执行此操作的其他事情表明,操作系统希望您只关闭主线程上的文件句柄,然后I/O线程应该从它的阻塞读取中出来然而,正如我在评论中所描述的,这似乎对我不起作用如果我在主线上这样做:
process.stdout.close()
我得到:
IOError: close() called during concurrent operation on the same file object.
…在主线上如果我在主线上这样做:
os.close(process.stdout.fileno())
我得到:
close failed in file object destructor: IOError: [Errno 9] Bad file descriptor
…稍后在主线程中尝试关闭文件句柄本身时。
最佳答案
我知道这是一篇老文章,但如果它仍然对任何人有帮助,我认为可以通过将subprocess.Popen实例传递给io_线程而不是输出流来解决您的问题。
如果这样做,那么可以用while True:
替换while process.poll() == None:
行。
process.poll()检查子流程返回代码;如果流程尚未完成,则没有子流程返回代码(即process.poll() == None
)。然后你就可以不用if line == "": break
。
我来这里的原因是因为我今天写了一个非常类似的剧本,我得到了:-IOError: close() called during concurrent operation on the same file object.
错误。
同样,如果有帮助的话,我认为我的问题源于(我的)io_线程执行了一些非常高效的垃圾收集,并关闭了我给它的一个文件句柄(我可能是错的,但现在它可以工作了…)我的不同之处在于它不是守护进程,而是在subprocess.stdout中迭代,而不是使用while循环。即:-
def io_thread(subprocess,logfile,lock):
for line in subprocess.stdout:
lock.acquire()
print line,
lock.release()
logfile.write( line )
我还应该提到,我将bufsize参数传递给subprocess.popen,这样它就得到了行缓冲。