2012-01-06 3 views
1

Я относительно новичок в python, но не для многопоточного программного обеспечения, поэтому я не могу объяснить конкретное поведение, которое я вижу. Моя программа довольно проста: я отслеживаю вывод команды linux «iostat» и что-то делаю в некоторой ситуации. Мой код выглядит следующим образом:Поведение странной нити

class SysMonitor(threading.Thread): 

def __init__(self): 
    threading.Thread.__init__(self) 
    self.isStopping = False 
    self.ioprocess = [] 

def run(self): 
    self.ioprocess = subprocess.Popen(['/usr/bin/iostat', '-p', 'sda', '60'], stdout=subprocess.PIPE) 
    p = self.ioprocess 
    i = 0 

    # Discard first output 
    while (i < 11): 
     p.stdout.readline() 
     i = i + 1 

    # Now keep on waiting on new output from iostat and then process it when it comes in 
    while (not self.isStopping): 
     select.select([p.stdout], [], []) 

     # Don't process the last output if we are stopping 
     if (self.isStopping): 
      print 'Quitting, discarding last buffer:' + str(self.isStopping) 
      continue 

     # do some p.stdout.readline() and process the data 

def stop(self): 
    self.isStopping = True 
    self.ioprocess.terminate() 

То, что я не понимаю, что когда я вызываю функцию «стоп», программа иногда выходит из строя, так как выбор свободен, потому что EOF записывается в буфере стандартного вывода, но isStopping по-прежнему ложно. Как это может произойти?

ответ

2

Если stop() вызывается вне темы, это может привести к случайным проблемам. Потому что когда вы назовете stop(), нить может быть в любом случае, в печати или в выборе и т. Д.

Просто переместите ваш terminate() в конце метода run(). Затем установка isStopping в True будет корректно покидать цикл, а затем завершить процесс.

Если вы хотите, чтобы ждать его, вы можете присоединиться к нитке:

def stop(self): 
    self.isStopping = True 
    self.join() 
+0

Проблема с помещением terminate в run() заключается в том, что программа не будет завершена немедленно по запросу, поскольку она может зависеть от вызова select.select. Поэтому в этом случае я мог бы застрять в ожидании до 1 минуты, чтобы программа закончилась. – goloap

+0

Затем вы можете использовать параметр тайм-аута в выборе или отправить сигнал ('import os, signal; os.kill (0, signal.SIGPIPE)') перед 'self.join()'. Документация по выбору показывает, что если сигнал получен, select() будет тайм-аут при приеме сигнала – tito

+0

Звучит неплохо, но это не работает. Я изменил свой код следующим образом: 'ready, _, _ = select.select ([p.stdout], [], []); if (self.isStopping или (не готов)): continue' и в функции stop (self) у меня есть self.isStopping = True; os.kill (0, signal.SIGPIPE); self.join() ' Сигнал достигает выбора, но переменная' ready' всегда является файловым дескриптором: _ [', mode 'rb' at 0xb2ce40>] _, поэтому я сталкиваюсь с той же проблемой , Поскольку сигнал делает тайм-аут выбора, не должен ли 'ready' быть пустым списком? Я делаю что-то неправильно? – goloap

2

Опираясь на tito's answer, и относительно вашего комментария, вы можете использовать тайм-аут в select.select:

while (not self.isStopping): 
     ready, _, _ = select.select([p.stdout], [], [], 5.0) 

     # Don't process the last output if we are stopping 
     if (self.isStopping): 
      print 'Quitting, discarding last buffer:' + str(self.isStopping) 
      continue 
     if ready: 
      # do some p.stdout.readline() and process the data 

    self.ioprocess.terminate() 

Выше, время ожидания составляет 5,0 секунд. Я полагаю, что это достаточно долго, чтобы не забивать систему и достаточно короткое для разумного завершения. Измените свой вкус.

+0

Это будет работать, но я чувствую, что это только работа от реальной проблемы: т. Е. Этот флаг isStopping не передается в поток до того, как процесс завершится, и я не понимаю, почему. – goloap

0

Если целью является завершение потока при завершении приложения, установите поток как демон.

Смежные вопросы