многопоточность.Condition.wait() не улавливает SIGTERM

#python #multithreading #conditional-statements #wait

#python #многопоточность #условные операторы #подождите

Вопрос:

У меня есть следующий код, который при выполнении ожидает прерывания на SIGINT , SIGTERM или SIGQUIT . Когда объект инициализируется, он создает threading.Condition() и acquires() это! Затем программа регистрирует обработчики сигналов, где notify() и release() вызывается при получении вышеупомянутых сигналов. После регистрации обработчиков сигналов он вызывает wait() переменную условия и блокирует.

Когда я попытался остановить программу с помощью Ctrl-C , она не ответила. Итак, _signal_handler() метод не был вызван.

 # start

from signal import signal, SIGINT, SIGTERM, SIGQUIT
from threading import Condition

class A:
    def __init__(self):
        self._termination_signal = Condition()
        self._termination_signal.acquire(blocking=0)

    def _signal_handler(self, signum, frame):
        print "Received terminate request - signal = {0}".format(signum)
        del frame
        self._termination_signal.notify()
        self._termination_signal.release()
        return

    def register_and_wait(self):
        signal(SIGINT, self._signal_handler)
        signal(SIGTERM, self._signal_handler)
        signal(SIGQUIT, self._signal_handler)
        print "Waiting to be interrupted!"
        self._termination_signal.wait()      # control blocks here!
        print "Notified!!"

def main():
    a = A()
    a.register_and_wait()

if __name__ == "__main__":
    main()

# end
  

Что я делаю не так?!

Ответ №1:

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

 from signal import pause, signal, SIGINT, SIGTERM, SIGQUIT

class A:
    def __init__(self):
        self._signum = 0

    def _signal_handler(self, signum, frame):
        print "Received terminate request - signal = {0}".format(signum)
        self._signum = signum
        return

    def wait_for_signal(self):
        signal(SIGINT, self._signal_handler)
        signal(SIGTERM, self._signal_handler)
        signal(SIGQUIT, self._signal_handler)
        print "Pause until signaled"
        while self._signum == 0:
            pause()

def main():
    a = A()
    a.wait_for_signal()

main()
  

Причина проверки self._signum заключается в том, что в случае пробуждения другого сигнала pause() . Простым примером этого было бы SIGALRM .

Комментарии:

1. signal.pause() только для Unix, лучше использовать какой-нибудь метод короткого ожидания, такой как time.sleep(1.0) или threading.Condition.wait(1.0) для переносимости.

2. @Tey’ Цель этого вопроса — избежать использования threading.Condition.wait , поскольку это вызывает этот сценарий взаимоблокировки, даже при вызове с таймаутом.