Функция wait () возвращается до обработки SIGCHLD? - PullRequest
0 голосов
/ 11 декабря 2018

Итак, у меня есть собственный обработчик для SIGCHLD и функция wait ().Ребенок выйдет после того, как родитель отправит ему сигнал SIGUSER2.В этом примере, когда дочерний элемент вызывает «exit (0)», родительский объект обрабатывает SIGCHLD и завершает работу или возможно, чтобы функция «wait ()» возвратилась до обработки сигнала SIGCHLD?

#include<stdio.h> 
#include<wait.h> 
#include<signal.h> 
pid_t pid; 
int counter = 0; 
void handler1(int sig) 
{ 
    printf("A\n");
    kill(pid, SIGUSER2);
} 
void handler2(int sig) 
{ 
    printf("B\n");
    exit(0); 
} 

int main() 
{ 
    signal(SIGUSR1, handler1);
    signal(SIGCHLD, handler2); 
    if ((pid = fork()) == 0) 
    { 
        signal(SIGUSR1, handler2);
        kill(getppid(), SIGUSR1); 
        while(1) ; 
    } 
    if ((p = wait(&status)) > 0) 
    { 
        printf("wait returned before SIGCHLD");
    } 
} 

1 Ответ

0 голосов
/ 11 декабря 2018

Из справочной страницы для wait можно получить EINTR:

EINTR WNOHANG не был установлен, и был разблокирован сигнал или SIGCHLD

Итак, если у SIGCHLD есть обработчик, и вы находитесь в wait, сигнал будет first .

Вот что имеет смысл.Потому что обработчики SIGCHLD могут свободно wait пожинать ребенка.Некоторые программы не делают wait в базовом коде, но полагаются на обработчик.

Как уже упоминалось, не выполняйте printf в обработчике [он делает malloc и все ставки выключены].Тем не менее, выполнение wait нормально [, некоторые системные вызовы в порядке / разрешены в обработчике].

В вашей программе было несколько проблем.Я немного рефакторинг.Это показывает, что SIGCHLD происходит до того, как wait завершается [как подразумевает man-страница].

Обратите внимание, что это довольно хороший тест, но окончательный может включать третий процесс, который должен убить исходного потомка ( после небольшого сна), чтобы позволить родителю войти в wait.

То есть killпроизойдет (в процессе 3), после того, как основной процесс введен wait.

Я не сделал этого, поэтому вот более простая версия:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>

pid_t pid;
volatile int gotsig = 0;

void
handler_cld(int sig)
{
    gotsig = 1;
}

void
handler_usr1(int sig)
{
    exit(0);
}

int
main()
{
    int status;

    signal(SIGUSR1, handler_usr1);
    signal(SIGCHLD, handler_cld);

    pid = fork();
    if (pid == 0) {
        while (1);
    }

    // kill the child
    kill(pid,SIGUSR1);

    if ((pid = wait(&status)) > 0) {
        printf("wait returned %s SIGCHLD\n",gotsig ? "after" : "before");
    }

    return 0;
}

ОБНОВЛЕНИЕ:

Вот более сложная версия, которая использует отдельный процесс "убийца", чтобы убить ребенка, но результаты те же:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>

volatile int gotsig = 0;

void
handler_cld(int sig)
{
    gotsig += 1;
}

void
handler_usr1(int sig)
{
    exit(0);
}

int
main()
{
    int status;

    signal(SIGUSR1, handler_usr1);
    signal(SIGCHLD, handler_cld);

    pid_t pidcld = fork();
    if (pidcld == 0) {
        while (1);
    }

    pid_t pidkill = fork();
    if (pidkill == 0) {
        sleep(1);
        // kill the child
        kill(pidcld,SIGUSR1);
        sleep(3);
        exit(0);
    }

    pid_t pidany;

    // wait for child
    if ((pidany = waitpid(pidcld,&status,0)) > 0) {
        printf("wait on child returned %s SIGCHLD\n",
            gotsig ? "after" : "before");
    }

    // wait for child
    if ((pidany = waitpid(pidkill,&status,0)) > 0) {
        printf("wait on killer returned %s SIGCHLD\n",
            gotsig ? "after" : "before");
    }

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...