Подтвердить что ты не робот

Изящно завершающие потоки Python

Я пытаюсь написать клиентскую программу unix, которая слушает сокет, stdin и чтение из файловых дескрипторов. Я назначаю каждую из этих задач отдельному потоку и успешно связываю их с "основным" приложением, используя синхронизированные очереди и семафор. Проблема в том, что когда я хочу завершить эти дочерние потоки, все они блокируют ввод. Кроме того, потоки не могут регистрировать обработчики сигналов в потоках, потому что в Python разрешен только основной поток выполнения.

Любые предложения?

4b9b3361

Ответ 1

Нет никакого хорошего способа обойти это, особенно когда поток блокируется.

У меня была аналогичная проблема (Python: как прервать блокирующий поток), и единственный способ остановить мои потоки - закрыть базовое соединение. Это привело к потоку, который блокировал повышение и исключение, а затем разрешил мне проверить флаг остановки и закрыть.

Пример кода:

class Example(object):
   def __init__(self):
       self.stop = threading.Event()
       self.connection = Connection()
       self.mythread = Thread(target=self.dowork)
       self.mythread.start()     
   def dowork(self):

        while(not self.stop.is_set()):
             try:
                  blockingcall()        
             except CommunicationException:
                  pass
   def terminate():
       self.stop.set()
       self.connection.close()
       self.mythread.join()

Еще одна вещь, которую следует отметить, - обычно операции блокировки, как правило, предлагают таймаут. Если у вас есть этот вариант, я бы подумал о его использовании. Мой последний комментарий: вы всегда можете установить поток на deamonic,

Из pydoc:

Поток может быть помечен как "поток демона". Значение этого флага заключается в том, что вся программа Python завершается, когда остаются только потоки демона. Начальное значение наследуется от создающего потока. Флаг может быть установлен через свойство демона.

Ответ 2

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

Сигналы для уничтожения потоков потенциально ужасны, особенно в C, особенно если вы выделяете память как часть потока, так как она не будет освобождена, когда этот конкретный поток погибнет (как и в куче процесса). В C нет сборки мусора, поэтому, если этот указатель выходит за пределы области видимости, он выходит из области видимости, память остается выделенной. Поэтому просто будьте осторожны с этим - сделайте это только в C, если вы собираетесь фактически убить все потоки и завершить процесс, чтобы память была возвращена в ОС - добавление и удаление потоков из потокового пула, например приведет к утечке памяти.

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

Как ни странно, я недавно сражался с тем же. Решение буквально не делает блокировки вызовов без тайм-аута. Итак, например, вы хотите идеально:

def threadfunc(running):

    while running:
        blockingcall(timeout=1)

где бег передается из управляющего потока - я никогда не использовал потоки, но я использовал многопроцессорность, и с этим вам действительно нужно передать объект Event() и проверить is_set(). Но вы просили шаблоны проектирования, что основная идея.

Затем, когда вы хотите, чтобы этот поток заканчивался, вы запускаете:

running.clear()
mythread.join()

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

Что вы делаете, если у вас есть блокирующий вызов без тайм-аута? Используйте асинхронную опцию и сон (как при вызове любого метода вы должны приостановить поток в течение определенного периода времени, чтобы вы не вращались), если вам нужно. Другого пути нет.