1
for r in range(0,REPEATS):
    p=subprocess.Popen(["ffplay", "-nodisp", "-autoexit", FILENAME])
    print "start audio"
    p.communicate()

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

Так же происходит, когда я закрываю консольное окно в собранной программе. Хотя тут странность, если я указал файл wav, то программа закроется, а если Mp3 то продолжит цикл.

Как сделать, чтобы child процессы игнорили сигналы?

Nicolas Chabanovsky
  • 51,426
  • 87
  • 267
  • 507
John Doe
  • 346
  • communicate возвращает кортеж (stdout, stderr). Если проверить stderr, то может получиться, что ffplay вылетает с ошибкой. – m9_psy Jun 04 '16 at 01:10
  • да нет там никакой ошибки, он просто принимает ^c и закрывается.в итоге освобождается очередь и запускается второй – John Doe Jun 04 '16 at 01:15

1 Answers1

1

Unix

На Unix можно передать функцию, которая включает игнорирование желаемых сигналов, через Popen(preexec_fn) параметр, например:

preexec_fn=lambda: signal.signal(signal.SIGINT, signal.SIG_IGN)

Если дочерний процесс устанавливает свой обработчик, то этот вызов не будет иметь эффект (обработчик всё равно позже будет переписан).

В этом случае вместо игнорирования сигнала, можно сделать так, чтобы по Ctrl-C сам сигнал просто не посылался процессу. Для этого его можно в другую группу процессов отправить (Ctrl-C только текущей активной группе посылается) задав start_new_session=True (или снова через preexec_fn=os.setsid (новая сессия), preexec_fn=os.setpgrp (только новая группа как правило):

import subprocess

subprocess.check_call('ping 127.0.0.1', shell=True, start_new_session=True)

Windows

На Винде preexec_fn не работает, а start_new_session=True по-прежнему передаёт Control-C.

signal(SIGINT, SIG_IGN) работает внутри самого Питон процесса и на Windows (KeyboardInterrupt не выбрасывается по Ctrl-C в этом процессе), но дочерний процесс, например, созданный с помощью multiprocessing.Process должен сам снова signal() вызывать (согласно результатам экспериментов на моей машине с Windows 7 и CPython 3.5.1).

Чтобы дочерний процесс не умирал по Ctrl-C, можно также новую группу создать (но со специфичным для Windows API):

subprocess.check_call('ping 127.0.0.1 -n 10',
                      creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)

Подробнее о перехвате сигналов в Питоне вообще и о Control-C в Питоне в частности.

jfs
  • 52,361
  • это только для Unix. в винде не будет работать – John Doe Jun 08 '16 at 23:54
  • @JohnDoe: вы пробовали? – jfs Jun 09 '16 at 01:15
  • да, давно...... – John Doe Jun 09 '16 at 03:17
  • ну вот, SIG_IGN то нету. нечем Игнорить SIGINT – John Doe Jun 09 '16 at 04:03
  • @JohnDoe SIG_IGN однозначно есть. Обновите вопрос и покажите полный traceback. Укажите точные версии Питона, Windows. – jfs Jun 09 '16 at 04:15
  • да где же он есть то https://msdn.microsoft.com/en-us/library/xdkz3x12.aspx – John Doe Jun 09 '16 at 04:22
  • и была бы ошибка хоть. просто ничего не делает и все – John Doe Jun 09 '16 at 04:29
  • @JohnDoe 1- вы понимаете что Питон может эмулировать функциональность отсутствующую на системе? 2- если нет ошибки, то что означает ваша фраза "SIG_IGN то нету" (например, в качестве доказательства вы могли бы AttributeError показать при попытке использования signal.SIG_IGN). – jfs Jun 09 '16 at 04:35
  • subprocess.Popen(["ffplay", "-nodisp", "-autoexit", '3.mp3'],stderr=sys.stdout,preexec_fn=init_worker) – John Doe Jun 09 '16 at 04:47
  • ValueError: preexec_fn is not supported on Windows platforms – John Doe Jun 09 '16 at 04:47
  • окей?........... – John Doe Jun 09 '16 at 04:47
  • @JohnDoe с этого и надо было начинать. (один шаг сделали). Шаг номер два: что происходит, если signal.signal(signal.SIGINT, signal.SIG_IGN) без preexec_fn в родителе вызвать? – jfs Jun 09 '16 at 04:55
  • он с ним и запускается, чтоб срабатывал except KeyboardInterrupt: – John Doe Jun 09 '16 at 05:15
  • @JohnDoe что эта ваша фраза означает: у вас в коде присутствует вызов signal, но вы попрежнему получаете KeyboardInterrupt при нажатии Ctrl+C? – jfs Jun 09 '16 at 05:40
  • нет не получаю, как только закончатся ffplay программу можно нормально закрыть – John Doe Jun 09 '16 at 05:47
  • @JohnDoe: я добрался до машины c Windows: signal(SIGINT, SIG_IGN) работает и на Windows, но если хочется Ctrl+C остановить, то можно CREATE_NEW_PROCESS_GROUP использовать. Обновил ответ. – jfs Jun 09 '16 at 18:20