Дочерний процесс получает СИГИНТ родителя
У меня есть одна простая программа, которая использует Qt Framework.
Он использует QProcess для выполнения RAR и сжатия некоторых файлов. В моей программе я ловлю SIGINT
и делаю что-то в своем коде, когда это происходит:
signal(SIGINT, &unix_handler);
Когда SIGINT
, который был предназначен для моей программы, и он завершает работу, прежде чем сжал все файлы.
Есть ли способ запустить процесс RAR так, чтобы он не получал SIGINT
, когда моя программа получает его?
Спасибо

Ответы - Дочерний процесс получает СИГИНТ родителя / Child process receives parent's SIGINT

24.07.2011 04:10:12
Что ты делаешь в своем кураторе? Существуют только определенные функции Qt, которые можно безопасно вызывать из обработчика сигналов unix. Эта страница в документации определяет, какие они.
Основная проблема заключается в том, что обработчик будет выполняться вне основного потока событий Qt. Эта страница также предлагает метод, чтобы справиться с этим. Я предпочитаю, чтобы обработчик "отправил" пользовательское событие в приложение и обработал его таким образом. Я опубликовал ответ, описывающий, как реализовать пользовательские события здесь .


24.07.2011 04:18:06
Если вы генерируете SIGINT
с помощью Ctrl + C в системе Unix, то сигнал передается всей группе процессов .
Вы должны использовать setpgid или setsid, чтобы поместить дочерний процесс в другую группу процессов, чтобы он не получал сигналы, генерируемые управляющим терминалом.
[Редактировать:]
Обязательно внимательно прочитайте раздел обоснование на странице setpgid. Это немного сложно, чтобы подключить все потенциальные условия гонки здесь.
Чтобы гарантировать 100%, что никакой SIGINT
не будет доставлен в ваш дочерний процесс, вам нужно сделать что-то вроде этого:
SIGINT
Строго говоря, каждый из этих шагов необходим. Вы должны заблокировать сигнал в случае, если пользователь нажмет Ctrl + C сразу после вызова #define CHECK(x) if(!(x)) { perror(#x " failed"); abort(); /* or whatever */ }
/* Block SIGINT. */
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
CHECK(sigprocmask(SIG_BLOCK, &mask, &omask) == 0);
/* Spawn child. */
pid_t child_pid = fork();
CHECK(child_pid >= 0);
if (child_pid == 0) {
/* Child */
CHECK(setpgid(0, 0) == 0);
execl(...);
abort();
}
/* Parent */
if (setpgid(child_pid, child_pid) < 0 && errno != EACCES)
abort(); /* or whatever */
/* Unblock SIGINT */
CHECK(sigprocmask(SIG_SETMASK, &omask, NULL) == 0);
. Вы должны вызвать fork
в дочернем случаеsetpgid
произойдет до того, как родитель успеет что-либо сделать. Вы должны вызвать fork
в родителе в случае, если родитель работает и кто-то нажимает Ctrl + C, прежде чем ребенок успевает что-либо сделать.
Последовательность выше неуклюжа, но она действительно обрабатывает 100% условий гонки.



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




assert
крайне неправильно! assert
условно включен или отключен, а когда отключен, он полностью устраняет свой аргумент. Вы должны использовать if(1!...) abort()
или ваш собственный макрос, обертывающий его.

/* or whatever */
подразумевало "какова бы ни была ваша политика обработки ошибок". Является ли это использование assert
"неправильным", полностью зависит от этой политики. (Там, где я работаю, мы никогда не компилируем с NDEBUG
, поэтому assert
можно использовать для случаев "этого никогда не должно произойти".)

assert
бумагу, не было. Так получилось, что в Linux вы обычно не контролируете, будет ли код компилироваться с NDEBUG
или нет, так как довольно легко вызвать configure CPPFLAGS="-O3 -fomit-frame-pointer -DNDEBUG"


assert
для "невозможных" случаев совершенно нормально и совершенно правильно. (И вы заметите, что этот код использует assert
для таких невозможных случаев; fork
, которая на самом деле может потерпеть неудачу, проверяется явно.) Ваше понижение основано на вашем личном мнении, а не на техническом факте или стандартной практике. Я добавил /* or whatever */
к assert
, чтобы сделать вас счастливыми,хотя это и не обязательно. Достаточно честно?

assert
не имеет побочных эффектов (нарушается здесь) и 2) условие может быть истинным только в том случае, если в программе есть ошибка (это не относится
к результату setpgid).

assert
, что оно подходит для выражений ,которые "истинны только в том случае, если в вашей программе есть ошибка". В этом контексте setpgid(0,0)
может завершиться ошибкой только в том случае, если имеется ошибка в библиотеке C или ядре, и проверка таких "невозможных" случаев с assert
вполне разумна. Но у тебя есть хорошая идея насчет побочных эффектов. Я думалassert(x)
гарантированно оценит x
, но я ошибался. Я вернулся к вашей версии.


