使用check_parent_select
时,在阅读器端关闭后,不会填写例外列表。
但是使用check_parent_poll
,在阅读器侧关闭后,它可以检测到管道断开。
有人知道根本原因吗?
#!/usr/bin/python2.7
import select
import sys
import os
log=open("./test.log","w")
(reader, writer) = os.pipe()
def check_parent_select(fh):
(rlist, wlist, xlist) = select.select([], [], [fh], 1)
if fh in xlist:
print "parent exit"
else:
print "parent OK"
def check_parent_poll(fh):
poller = select.poll()
EVENTS = select.POLLERR
poller.register(fh)
events = poller.poll()
for fd, flag in events:
if flag & select.POLLERR:
print "parent exit"
else:
print "parent OK"
open_file = os.fdopen(writer, "w")
check_parent_select(open_file)
os.close(reader)
check_parent_select(open_file)
使用strace跟踪选择功能,选择无法检测管道关闭。
pipe([4,5])= 0
选择(6,[],[],[5],{1,0})= 0(超时)
写(1,“父OK \ n”,10parent OK
关闭(4)= 0
选择(6,[],[],[5],{1,0})= 0(超时)
答案 0 :(得分:1)
它有点隐藏,但是如果你按照the documentation,它会变得更清晰:select()
检查挂起错误条件,即使文件描述符无法使用的错误条件,但只有在错误发生后才会发生。
关闭读取结束后,您尚未对管道进行任何操作,这会导致错误情况。 writer
仍有有效的操作:例如,您可以关闭fd。因此管道尚未处于错误状态。
关闭作者端时更容易识别问题:即使在关闭之后,管道缓冲区中也可能存在可读数据,但尚未消耗。在这种情况下,您希望read()
在0
上返回EOF
,而不是-1
以获取错误。另一方表现相似,即使你真的无法写入读取结束已经关闭的管道。
行为与socket.socketpair()
(或实际套接字)相同:只要尚未执行任何无效操作,就没有错误条件。
log=open("./test.log","w")
(reader, writer) = socket.socketpair()
def check_parent_select(fh):
(rlist, wlist, xlist) = select.select([], [], [fh], 1)
if fh in xlist:
print "parent exit"
else:
print "parent OK"
def check_parent_poll(fh):
poller = select.poll()
EVENTS = select.POLLERR
poller.register(fh)
events = poller.poll()
for fd, flag in events:
if flag & select.POLLERR:
print "parent exit"
else:
print "parent OK"
check_parent_select(writer)
reader.close()
check_parent_select(writer)
答案 1 :(得分:0)
缓解此意外结果的快速解决方法是在writer中侦听读取事件。更好的解决方法是使用pselect()并监听SIG_PIPE,但是afaik python没有pselect()
我将其称为“意外”,因为您首先想到的是,读取结束的结束将作为作者的例外信号发出。从作者的角度来看,只要它还有一些东西可以写,它可能确实是一个例外情况。但是,从操作系统的角度来看,这只是文件描述符的简单close()。
如果您阅读poll()系统调用的联机帮助页,您将发现将通过在读取事件列表中标记POLLHUP位来发出文件描述符的关闭信号。 select()具有相同的行为,只是它没有设置用于标识close()调用的特定位。
#!/usr/bin/python2.7
import select
import sys
import os
import time
log=open("./test.log","w")
(reader, writer) = os.pipe()
def check_parent_select(fh):
(rlist, wlist, xlist) = select.select([fh], [fh], [fh], 1)
print(rlist, wlist, xlist)
if fh in rlist:
print "oh i'm just writing. error"
if fh in xlist:
print "parent exit"
else:
print "parent OK"
def check_parent_poll(fh):
poller = select.poll()
EVENTS = select.POLLERR
poller.register(fh)
events = poller.poll()
for fd, flag in events:
if flag & select.POLLERR:
print "parent exit"
else:
print "parent OK"
#open_file = os.fdopen(writer, "w")
check_parent_select(writer)
os.close(reader)
#time.sleep(3)
check_parent_select(writer)
所以当管道关闭时,你会在作者中得到一个读取事件:
python2 t1.py
([], [5], [])
parent OK
([5], [5], [])
oh i'm just writing. error
parent OK