select对python中的管道不起作用?

时间:2016-08-04 05:35:36

标签: python linux

使用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(超时)

2 个答案:

答案 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