Обработка KeyboardInterrupt при работе с PyGame

Я написал небольшое приложение Python, в котором я использую PyGame для отображения простой графики.

У меня есть несколько простой цикл PyGame, идущий в основе моего приложения, например:

stopEvent = Event()

# Just imagine that this eventually sets the stopEvent
# as soon as the program is finished with its task.
disp = SortDisplay(algorithm, stopEvent)

def update():
    """ Update loop; updates the screen every few seconds. """
    while True:
        stopEvent.wait(options.delay)
        disp.update()
        if stopEvent.isSet():
            break
        disp.step()

t = Thread(target=update)
t.start()

while not stopEvent.isSet():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            stopEvent.set()

Он отлично работает и при нормальном завершении программы; если окно PyGame закрывается, приложение закрывается; если приложение завершает свою задачу, оно закрывается.

Проблема, с которой я столкнулся, заключается в том, что если я Ctrl - C в консоли Python, приложение выдает KeyboardInterrupt, но продолжает работать.

Таким образом, возникает вопрос: что я сделал не так в цикле обновления и как исправить это, чтобы KeyboardInterrupt прекратил работу приложения?


person Sebastian Paaske Tørholm    schedule 12.05.2010    source источник


Ответы (2)


Как насчет изменения вашего последнего цикла на ...:

while not stopEvent.isSet():
    try:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                stopEvent.set()
    except KeyboardInterrupt:
        stopEvent.set()

т.е. убедитесь, что вы улавливаете прерывания клавиатуры и обрабатываете их так же, как событие выхода.

person Alex Martelli    schedule 12.05.2010
comment
Казалось бы, это сработает, если я сделаю то же самое внутри самого потока. Однако мне кажется немного странным, что я должен явно перехватывать KeyboardInterrupt. - person Sebastian Paaske Tørholm; 12.05.2010
comment
@Sebastian, KeyboardInterrupt всегда переходит в основной поток, поэтому я не уверен, почему вы должны также перехватывать его во второстепенных потоках. - person Alex Martelli; 12.05.2010
comment
На самом деле это может показаться так, не может повторить то, что я получил ранее. Возможно, мои файлы не синхронизировались. Спасибо. - person Sebastian Paaske Tørholm; 12.05.2010

Изменяя ответ Алекса, обратите внимание, что вы, вероятно, захотите сделать это для всех исключений, чтобы гарантировать, что вы завершите поток, если основной поток выходит из строя по какой-либо причине, а не только KeyboardInterrupt.

Вам также необходимо переместить обработчик исключений, чтобы избежать состояния гонки. Например, при вызове stopEvent.isSet () может возникнуть KeyboardInterrupt.

try:
    t = Thread(target=update)
    t.start()

    while not stopEvent.isSet():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                stopEvent.set()
finally:
    stopEvent.set()

Это, наконец, проясняет: вы можете сразу сказать, что событие всегда будет установлено независимо от того, как вы выйдете из этого блока кода. (Я предполагаю, что установка события дважды безвредна.)

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

person Glenn Maynard    schedule 12.05.2010