сигнал вызова после вилки - PullRequest
6 голосов
/ 28 января 2011

Есть ли разница между "списком кодов 1" и "списком кодов 2"?Поскольку в листинге 1, дочерний процесс может перехватить сигнал SIGTERM и успешно завершиться.Но код списка 2 прерывается по сигналу SIGTERM.

Я использую Linux и C.

Листинг 1

if (signal(SIGTERM, stopChild) == SIG_ERR) {
    printf("Could not attach signal handler\n");
    return EXIT_FAILURE;
}
pid = fork();

Листинг 2

pid = fork();
if (signal(SIGTERM, stopChild) == SIG_ERR) {
    printf("Could not attach signal handler\n");
    return EXIT_FAILURE;
}

Странно то, что в листинге 2 как дочерний, так и родительский процесс устанавливает обработчик сигнала для SIGTERM .Итак, это должно сработать.Не правда ли?

Ответы [ 3 ]

5 голосов
/ 01 февраля 2011

Если вы отправляете SIGTERM от родителя, конечный результат зависит от порядка планирования процессов.

Если ребенок назначен первым, все работает:

                                                +---------------+
                                                | pid = fork(); |
                                                +-------+-------+
                   parent                               |                               child
                          +-----------------------------+-----------------------------+
                          |                                                           |
                          |                                 +-------------------------+--------------------------+
                          |                                 | if (signal(SIGTERM, stopChild) == SIG_ERR) {       |
                          |                                 |       printf("Could not attach signal handler\n"); |
                          |                                 |       return EXIT_FAILURE;                         |
                          |                                 | }                                                  |
                          |                                 +-------------------------+--------------------------+
                          |                                                           |
                          .                                                           .
                          .                                                           .
                          .                                                           .
                          |                                                           |
+-------------------------+--------------------------+                                |
| if (signal(SIGTERM, stopChild) == SIG_ERR) {       |                                |
|       printf("Could not attach signal handler\n"); |                                |
|       return EXIT_FAILURE;                         |                                |
| }                                                  |                                |
+-------------------------+--------------------------+                                |
                          |                                                           |
                          |                                                           |
                          |                                                           |
            +-------------+-------------+                                             |
            | if (pid > 0) {            |                                             |
            |       kill(pid, SIGTERM); |                                             |
            | }                         |                                             |
            +-------------+-------------+                                             |
                          |                                                           |
                          |                                                           |
                          |                                                           |

Но если сначала назначить парен, ребенок, возможно, не успел настроить обработчик сигнала:

                                                +---------------+
                                                | pid = fork(); |
                                                +-------+-------+
                   parent                               |                               child
                          +-----------------------------+-----------------------------+
                          |                                                           |
+-------------------------+--------------------------+                                |
| if (signal(SIGTERM, stopChild) == SIG_ERR) {       |                                |
|       printf("Could not attach signal handler\n"); |                                |
|       return EXIT_FAILURE;                         |                                |
| }                                                  |                                |
+-------------------------+--------------------------+                                |
                          |                                                           |
                          |                                                           |
                          |                                                           |
            +-------------+-------------+                                             |
            | if (pid > 0) {            |                                             |
            |       kill(pid, SIGTERM); |                                             |
            | }                         |                                             |
            +-------------+-------------+                                             |
                          |                                                           |
                          .                                                           .
                          .                                                           .
                          .                                                           .
                          |                                                           |
                          |                                 +-------------------------+--------------------------+
                          |                                 | if (signal(SIGTERM, stopChild) == SIG_ERR) {       |
                          |                                 |       printf("Could not attach signal handler\n"); |
                          |                                 |       return EXIT_FAILURE;                         |
                          |                                 | }                                                  |
                          |                                 +-------------------------+--------------------------+
                          |                                                           |
                          |                                                           |
                          |                                                           |

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

3 голосов
/ 28 января 2011

Во-первых, signal () устарел, лучше использовать sigaction () . Я не думаю, что fork () может полностью исчезнуть, так как его используют многие вещи, но sigaction () обеспечивает гораздо более приятный интерфейс.

Поведение, которое вы испытываете, обычно вызывается вызовом fork () из потока. POSIX обращается к этому конкретно :

Процесс должен быть создан с одна нить Если многопоточный процесс вызывает fork (), новый процесс должен содержать копию вызова поток и все его адресное пространство, возможно, включая состояния мьютексы и другие ресурсы. Следовательно, чтобы избежать ошибок, дочерний процесс может выполняться только безопасные асинхронные сигналы операции до такое время как одна из функций exec называется. [THR] Обработчики вил могут быть установлены с помощью Функция pthread_atfork () для того, чтобы поддерживать инварианты приложений через вызов fork ().

Когда приложение вызывает fork () из обработчик сигнала и любой из форка обработчики, зарегистрированные pthread_atfork () вызывает функцию, которая не асинхронный сигнал-безопасный, поведение не определено.

Это означает, что вместо того, чтобы наследовать копию всего адресного пространства родителя, вы наследуете только копию вызывающего threads адресного пространства, которое не содержит ваших обработчиков. Возможно, вы действительно (возможно, даже невольно) вызываете fork () из потока.

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

0 голосов
/ 28 января 2011

Ну, в соответствии с man fork:

Функции fork (), fork1 () и forkall () создают новый процесс. Адресное пространство нового процесса (дочерний процесс) является точной копией адресного пространства вызывающего процесса (родительский процесс). Дочерний процесс наследует следующие атрибуты от родительского процесса:

...

o настройки обработки сигналов (то есть SIG_DFL, SIG_IGN, SIG_HOLD, адрес функции)

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

...