2012-10-31 99 views
3

我正在用python編寫程序。我希望從stdin讀取,並處理sigchld。我想處理任何一個輸入,而不是旋轉(對輸入進行推測性採樣)。python信號,中斷系統調用

我無法在每次通話時捕獲由信號中斷的sys-call。

我該怎麼做呢?我可以在沒有嘗試/除外的情況下讓這個工作嗎?

我的主要擔心不是嘗試/除了我在代碼到目前爲止。但是,在程序中我將需要其他代碼。它對我來說似乎不是模塊化的。

下面是一些測試代碼:

#!/usr/bin/python 

from time import sleep 
import select 
import signal 
import fcntl 
import os 
import sys 

pipe_r, pipe_w = os.pipe() 
flags = fcntl.fcntl(pipe_w, fcntl.F_GETFL, 0) 
flags = flags | os.O_NONBLOCK 
fcntl.fcntl(pipe_w, fcntl.F_SETFL, flags) 

signal.signal(signal.SIGCHLD, lambda x,y: None) 
signal.signal(signal.SIGALRM, lambda x,y: None) 
signal.siginterrupt(signal.SIGCHLD,False) #makes no difference 
signal.siginterrupt(signal.SIGALRM,False) #makes no difference 
signal.set_wakeup_fd(pipe_w) 
signal.setitimer(signal.ITIMER_REAL, 2, 2) 

poller = select.epoll() 
poller.register(pipe_r, select.EPOLLIN) 
poller.register(sys.stdin, select.EPOLLIN) 

print "Main screen turn on" 
while True: 
    events=[] 
    try: 
     events = poller.poll() 
     try: 
      for fd, flags in events: 
       ch=os.read(fd, 1) 
       if fd==pipe_r: 
        sys.stdout.write("We get Signal") 
       if fd==sys.stdin.fileno(): 
        sys.stdout.write(ch) 
       sys.stdout.flush() 
     except IOError as e: 
      print "exception loop" + str(e) 
    except IOError as e: 
     print "exception poll" + str(e) 

版本:

#python --version 
python 2.7.3 
#uname -a 
Linux richard 3.2.0-32-generiC#51-Ubuntu SMP Wed Sep 26 21:33:09 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux 

回答

1

我寫了一個python庫,將信號呈現爲流,因此我可以使用select/poll/epoll等。它使用libc(Gnu C庫)來完成艱苦的工作。希望它是有用的。

https://github.com/richard-delorenzi/pysigstream

如果你想改善它,那麼你可以fork它,請發送拉請求。

6

是的,你要對這個正確的方式。 (好吧,我可能會使用selectpoll代替epoll,因爲那時你的代碼將被移植到非Linux平臺...)

我在這裏假設兩個或兩個以上FDS輪詢本質上是必要的設計。如果您只添加了epoll循環來處理信號,那麼該部分不是必需的;所有你需要的是一個簡單的EINTR環繞read調用。但是,一旦你有一個用於其他目的的管道,把它連接起來作爲信號喚醒管是一個合理的事情,然後你的和你做的所有事情都隱含在從多個fds中讀取。

無論哪種方式,你真的無法避免try塊。 (這不是真的,你可以總是阻止信號sigblock/sigprocmask /etc.-they're不在Python的signal模塊中,但你總是可以使用​​這些模塊,但是你通常需要更多的代碼, try/finally而不是try/except,並且您的代碼變得更難以調試,所以除了少數情況下處理代碼不能被中斷且必須)

這是POSIX的一個標準功能,許多系統調用可以被信號中斷,在這種情況下,它們會以EINTR失敗。

大多數特定的平臺將可中斷的調用列表限制爲比POSIX允許的更小的調用列表,因此您必須查看linux文檔以確定EINTR安全的確切內容,但是,方法家族以及read/recv/write/send和朋友幾乎肯定是不安全的。

使用siginterrupt可能會有所幫助,但它不能解決問題。特別是,不需要重新啓動而不需要中斷,並且在某些情況下需要中斷或完成部分結果而不是重新啓動。我很肯定selectpoll從不可重新啓動,所以很有可能epoll家族不是,但你必須檢查。無論如何,大多數BSD派生默認情況下都會重啓,所以如果linux是相同的,那麼你不會改變任何東西。Python可以用隱式EINTR循環包裝所有這些,我相信一些更高級別的方法(如sendall)可以這樣做,但是較低級別的方法不會。但你可以自己包裝。例如(從我的頭頂,未經測試):

def dopoll(poller): 
    while True: 
     try: 
      return poller.poll() 
     except IOError as e: 
      if e.errno != EINTR: 
       raise 

然後,你處處會叫poll,叫dopoll代替。

+0

我的主要擔心不是嘗試/除了我在代碼中到目前爲止。但是,在程序中我將需要其他代碼。它對我來說似乎不是模塊化的。 –

+0

這就是爲什麼你爲每個系統調用寫封裝的原因。所以你需要一個嘗試/除了在這六種包裝中的每一種,但你不需要嘗試/除了數百個呼叫中的任何一個。 – abarnert

+0

你是說我需要一個包裝每個系統調用或只是爲了一些? –