Как правильно использовать поток обратного отсчета, как я могу остановить его преждевременно?

Threading работает не так, как я ожидаю.

У меня есть рабочее решение, где я контролирую, когда холодильник открывается и закрывается с помощью малины Pi и язычкового переключателя (воспроизведение звука неоспоримо и приостановлено). Теперь я хотел добавить таймер, чтобы что-то сделать, когда дверь слишком долго открывалась. Я решил начать поток, который будет спать в течение x секунд, прежде чем действие предупреждения будет хорошей идеей. Я бы убил нить сигналом, когда переключатель снова закрыт.

Мой подход терпит неудачу. Запуск потока CountDown запускается, но команда завершения сигнала запуска выполняется, но не имеет никакого эффекта. Кроме того, команды, следующие за c.terminate() , не выполняются. Я посмотрел примеры для потокования, но они, похоже, для более сложных ситуаций. Что мне не хватает?

Код:

 #!/usr/bin/env python2.7 import threading, subprocess, sys, time, syslog import RPi.GPIO as GPIO sound = "/home/pi/sounds/fridge_link.mp3" # sound to play while switch is open cmd = ['mplayer', '-nolirc', '-noconsolecontrols', '-slave', '-quiet', sound] # command to play sound lim = 10 # seconds until warning # thread for countdown (should be interruptable) # based on http://chimera.labs.oreilly.com/books/1230000000393/ch12.html#_solution_197 class CountdownTask: def __init__(self): self._running = True def terminate(self): self._running = False print("thread killed") def run(self, n): print("start timer") time.sleep(n) ## action when timer isup print("timer ended") c = CountdownTask() t = threading.Thread(target=c.run, args=(lim,)) t.daemon = True p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) p.stdin.write('\npausing_keep pause\n') REED = 27 # data pin of reed sensor (in) # GPIO setup GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(REED,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) def edge(channel): if GPIO.input(REED): print("detect close") c.terminate() p.stdin.write('\npause\n') pass else: print("detect open") t.start() p.stdin.write('\npausing_toggle pause\n') def main(): GPIO.add_event_detect(REED, GPIO.BOTH,callback=edge,bouncetime=1000) while True: time.sleep(0.2) pass #------------------------------------------------------------ if __name__ == "__main__": main() 

Новая версия:

 #!/usr/bin/env python2.7 import threading, subprocess, sys, time, syslog import RPi.GPIO as GPIO sound = "/home/pi/sounds/fridge_link.mp3" # sound to play while switch is open cmd = ['mplayer', '-nolirc', '-noconsolecontrols', '-slave', '-quiet', sound] # command to play sound lim = 10 # seconds until warning # thread for countdown (should be interruptable) class CountdownTask: global dooropen def __init__(self): self._running = True def terminate(self): self._running = False print("thread killed") def run(self, n): while self._running and dooropen == False: time.sleep(0.2) pass while self._running and dooropen: print("start timer") time.sleep(n) ## action when timer isup print("timer ended") c = CountdownTask() t = threading.Thread(target=c.run, args=(lim,)) t.daemon = True p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE) p.stdin.write('\npausing_keep pause\n') REED = 27 # data pin of reed sensor (in) # GPIO setup GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(REED,GPIO.IN, pull_up_down=GPIO.PUD_DOWN) dooropen = False # assuming door's closed when starting def edge(channel): global dooropen if GPIO.input(REED): # * no longer reached if dooropen == False: # catch fridge compressor spike print("false close alert") return p.stdin.write('\npause\n') dooropen = False pass else: print("detect open") if dooropen == True: print("false open alert") return p.stdin.write('\npausing_toggle pause\n') dooropen = True def main(): GPIO.add_event_detect(REED, GPIO.BOTH,callback=edge,bouncetime=1000) t.start() while True: time.sleep(0.2) pass #------------------------------------------------------------ if __name__ == "__main__": main() 

Скорректированный раздел, работающий сейчас:

  def run(self, n): while self._running and dooropen == False: time.sleep(0.2) pass while self._running and dooropen: time.sleep(n) if dooropen: ## action when timer isup 

One Solution collect form web for “Как правильно использовать поток обратного отсчета, как я могу остановить его преждевременно?”

Ваш запрограммированный механизм завершения потока через self._running не работает, потому что вы не проверяете состояние self._running в self._running run() протектора (что фактически выполняется в примере, на который вы ссылались).

Регулярный опрос добавляет сложности, которые здесь не нужны. Вы должны структурировать свою логику по-другому, что является простым и надежным. Пример кода:

 import threading import time dooropen = True def warnafter(timeout): time.sleep(timeout) if dooropen: print("Warning!") t = threading.Thread(target=warnafter, args=(2,)) t.start() time.sleep(1) dooropen = False t.join() - import threading import time dooropen = True def warnafter(timeout): time.sleep(timeout) if dooropen: print("Warning!") t = threading.Thread(target=warnafter, args=(2,)) t.start() time.sleep(1) dooropen = False t.join() 

Измените time.sleep(1) на time.sleep(3) и time.sleep(3) предупреждение. Почему это работает и как это переводится в ваш прецедент?

Прежде всего, давайте дадим имена вещей. У вас есть свой основной поток и «предупреждающий поток». Это краеугольные камни архитектуры в моем примере кода:

  • У вас есть общее состояние между двумя потоками, указывающее, открыта ли дверь или нет, что означает, следует ли выпустить предупреждение или нет. Назовем это государственным dooropen , и это может быть True или False . Это переменная, доступная как в области основного потока, так и в области, к которой имеет доступ поток уведомлений. То есть, он живет в общей памяти.

  • Это ваше соглашение: dooropen записывается только из основного потока. Предупреждающий поток только читает его.

  • Создайте свой поток предупреждений, когда вы считаете, что это подходящее время. Заставьте его спать (точное время сна может быть ненадежным, особенно на встроенных системах).

  • Важнейшая часть: прямо перед тем, как поднимать тревогу в потоке предупреждения, проверьте dooropen состояние dooropen . Если not dooropen , просто не поднимайте будильник!

Вы видите две разные парадигмы?

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

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

Учитывая последнюю парадигму, если сообщается, что поток предупреждений не выполняет свое действие, он молча закрывается сам по себе. Понятие «прекращение потока извне» не требуется!

На практике вам понадобится немного более продвинутая концепция, в которой поток предупреждений имеет свой active переключатель. То есть ваш основной поток может деактивировать отдельные потоки предупреждений контролируемым образом. См. Этот пример:

 import threading import time class WarnThread(threading.Thread): def __init__(self, timeout, name): threading.Thread.__init__(self) self._timeout = timeout self.active = True self.name = name self.start() def run(self): self._warnafter() def _warnafter(self): time.sleep(self._timeout) if self.active: print("WarnThread %s: Warning after timeout" % self.name) ws = [WarnThread(2, i) for i in range(5)] # Simulate spending some time doing other things, # such as responding to external events. time.sleep(1) # Selectively deactivate some of the warn threads. ws[0].active = False ws[2].active = False for w in ws: w.join() 

Вывод:

 WarnThread 4: Warning after timeout WarnThread 1: Warning after timeout WarnThread 3: Warning after timeout 
  • Можно ли использовать Intvar / DoubleVar в потоке Python?
  • Почему GridSearchCV в scikit-learn порождает так много потоков
  • Насколько эффективна потоковая обработка в Python?
  • как я могу использовать uwsgi web.py для запуска фоновой функции?
  • Qt: Не зарегистрировано qRegisterMetaType ()
  • Как выйти из многопоточной программы?
  • PyQt: moveToThread не работает при использовании частичного () для слота
  • многопроцессорные схемы графического интерфейса для борьбы с блокировкой «Неответ»
  • PyQt: обновление GUI из обратного вызова
  • Откладывание функций в python
  • Python: threading + curve_fit: аргумент null для внутренней процедуры
  •  
    Interesting Posts for Van-Lav

    Сохранять все записи, за исключением одного ключа python

    Как я могу имитировать вход для stdin для pyunit?

    Сравнение двух массивов, полученных в третьем массиве

    PyUSB dev.set_configuration ()

    Как я могу подчеркнуть тест / нагрузку на клиентское серверное приложение?

    Каков самый быстрый способ добавить данные в список без дублирования в python (2.5)

    Фильтр Django Admin для свойства Foreign Key

    python – возможно ли расширить набор вещей, которые могут быть сериализованы xml-rpc?

    Regex в python: возможно ли получить совпадение, замену и окончательную строку?

    Загрузка огромных файлов XML и обращение к MemoryError

    Выполнение readonly для существующего поля, но позволяющее добавлять при создании новой встроенной строки в django admin

    Каков наиболее эффективный способ вставки словарей / списков Python в базу данных SQL?

    Сервер разработки приложений не обновляет код при изменении

    Sys.settrace Python не будет создавать события c_call

    Django в Google App Engine с облачным SQL в среде dev

    Python - лучший язык программирования в мире.