2009-12-14 20 views
2

J'écris du code pour tester des programmes multithread (devoirs de l'étudiant - probablement buggés), et je veux être capable de détecter quand ils sont bloqués. Lorsqu'ils s'exécutent correctement, les programmes produisent régulièrement des sorties sur stdout, ce qui rend la procédure assez simple: si aucune sortie n'a lieu pendant X secondes, tuez-la et signalez un blocage. Voici le prototype de fonction:Outils pour implémenter un timer de surveillance en 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.""" 

Je peux écrire moi-même, mais il est un peu difficile à trouver à droite, donc je préfère utiliser le code existant si possible. Quelqu'un a écrit quelque chose de similaire?


Ok, voir la solution ci-dessous. Le module de sous-processus peut également être pertinent si vous faites quelque chose de similaire.

Répondre

5

Vous pouvez utiliser expect (tcl) ou pexpect (python) pour cela.

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

est ici très peu testé, mais apparemment de travail, solution:

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

Une autre solution:

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; 

Utilisation si vous voulez faire fonctionner que se termine en moins de x secondes :

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

Utilisation si vous exécutez régulièrement quelque chose et voulez vous assurer qu'il est exécuté au moins tous les y secondes:

def myHandler(): 
    print "Watchdog expired" 

watchdog = Watchdog(y, myHandler) 

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