отправка сигнала дочерним процессам почему-то потерялась. Результат изменения функции сна странным образом - PullRequest
3 голосов
/ 12 сентября 2011

Я начинающий C dev. Я пытаюсь понять, каким образом С управляет убийствами, сигналами и сном. См:

void son1_handler(int sig)
{
    printf("[SON1]:");
    fflush(stdout);
}

void son2_handler(int sig)
{
    printf("[SON2]:");
    fflush(stdout);
}

int main(int argc, char **argv)
{
    pid_t son1, son2;
    son1 = fork();
    if (son1 == 0)
    {
        while (1)
        {
            signal(SIGUSR1, son1_handler);
        };
    }

    son2 = fork();
    if (son2 == 0)
    {
        while (1)
        {
            signal(SIGUSR2, son2_handler);
        };
    }

    while (1)
    {
        sleep(1);
        kill(son1, SIGUSR1);
        kill(son2, SIGUSR2);
    }
}

Моя цель - напечатать: [SON1]: [SON2]: [SON1]: [SON2] .... С кодом выше иногда получалось, иногда [SON2]: [SON1]: [SON2] ...

Я думал, что меняюсь, используя сон между убийствами:

kill(son1, SIGUSR1);
sleep(1);
kill(son2, SIGUSR2);

но неожиданно результат был: [SON2]: [SON2]: [SON2]: [SON2]: [SON2] ....

Я думаю, что я что-то неправильно понимаю о сне, убийстве или сигнале. Есть ли у вас какие-либо идеи? Действительно спасибо заранее.

1 Ответ

1 голос
/ 12 сентября 2011

Это связано с планированием процесса.

Когда вы «отправляете» сигнал, устанавливается соответствующий бит на печатной плате ( Блок управления процессом ).и затем, когда процесс, которому был отправлен сигнал, запланирован, он проверяет сигналы и запускает обработчики.

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

Sleep просто позволяет операционной системе «переключать контекст», то есть разрешать запуск другой программы.Итак, в этом случае

kill(son1, SIGUSR1);
sleep(1);
kill(son2, SIGUSR2);

Вы отправляете сигнал son1, а затем переводите родительский процесс в спящий режим.Однако не обязательно, чтобы процесс son1 был запланирован перед родительским процессом снова.Это зависит от планировщика процессов операционной системы.Вам нужно будет использовать какой-нибудь мьютексный механизм, например семафоры, если вы хотите добиться синхронизации, как вы упомянули.

Надеюсь, что все прояснится.

Редактировать: Также в Linux обработчики сигналовоставаться зарегистрированным даже после последующих вызовов к ним, в отличие от Unix, где обработчики сигналов становятся незарегистрированными после одного вызова.Это означает, что вы должны вызывать signal () только один раз в своих дочерних программах вместо вызова в каждой итерации ваших циклов while ().

...