2009-12-14 3 views
2

Я пишу код для тестирования многопоточных программ (домашняя работа студентов - скорее всего, ошибка) и хочу иметь возможность обнаруживать, когда они зашли в тупик. При правильном запуске программы регулярно выводят вывод в stdout, что делает его довольно простым: если нет выхода в течение X секунд, убейте его и сообщите о взаимоблокировке. Вот прототип функции:Инструменты для реализации сторожевого таймера в python

def run_with_watchdog(command, timeout): 
    """Run shell command, watching for output. If the program doesn't 
    produce any output for <timeout> seconds, kill it and return 1. 
    If the program ends successfully, return 0.""" 

Я могу написать это сам, но это немного сложнее, чтобы получить права, поэтому я предпочел бы использовать существующий код, если это возможно. Кто-нибудь написал что-то подобное?


Хорошо, см. Решение ниже. Модуль подпроцесса может также иметь значение, если вы делаете что-то подобное.

ответ

5

Для этого вы можете использовать expect (tcl) или pexpect (python).

import pexpect 
c=pexpect.spawn('your_command') 
c.expect("expected_output_regular_expression", timeout=10) 
1

Вот очень немного тестируется, но, казалось бы, работая, решение:

import sys 
import time 
import pexpect 
# From http://pypi.python.org/pypi/pexpect/ 

DEADLOCK = 1 

def run_with_watchdog(shell_command, timeout): 
    """Run <shell_command>, watching for output, and echoing it to stdout. 
    If the program doesn't produce any output for <timeout> seconds, 
    kill it and return 1. If the program ends successfully, return 0. 
    Note: Assumes timeout is >> 1 second. """ 

    child = pexpect.spawn('/bin/bash', ["-c", shell_command]) 
    child.logfile_read = sys.stdout 
    while True: 
     try: 
      child.read_nonblocking(1000, timeout) 
     except pexpect.TIMEOUT: 
      # Child seems deadlocked. Kill it, return 1. 
      child.close(True) 
      return DEADLOCK 
     except pexpect.EOF: 
      # Reached EOF, means child finished properly. 
      return 0 
     # Don't spin continuously. 
     time.sleep(1) 

if __name__ == "__main__": 
    print "Running with timer..." 
    ret = run_with_watchdog("./test-program < trace3.txt", 10) 
    if ret == DEADLOCK: 
     print "DEADLOCK!" 
    else: 
     print "Finished normally" 
0

Другое решение:

class Watchdog: 
    def __init__(self, timeout, userHandler=None): # timeout in seconds 
    self.timeout = timeout 
    if userHandler != None: 
     self.timer = Timer(self.timeout, userHandler) 
    else: 
     self.timer = Timer(self.timeout, self.handler) 

    def reset(self): 
    self.timer.cancel() 
    self.timer = Timer(self.timeout, self.handler) 

    def stop(self): 
    self.timer.cancel() 

    def handler(self): 
    raise self; 

Использование если вы хотите, чтобы убедиться, что функция заканчивается менее чем x секунд :

watchdog = Watchdog(x) 
try 
    ... do something that might hang ... 
except Watchdog: 
    ... handle watchdog error ... 
watchdog.stop() 

Использование, если вы регулярно выполняете что-то и хотите удостовериться, что оно выполнено как минимум каждые y секунд:

def myHandler(): 
    print "Watchdog expired" 

watchdog = Watchdog(y, myHandler) 

def doSomethingRegularly(): 
    ... 
    watchdog.reset()