Unix表示奇怪的行为。 (儿童退出多次)

时间:2016-04-09 15:45:44

标签: c unix signals fork

我正在练习使用unix信号编程,我是新手, 所以我写了以下程序:http://wklej.org/id/2253905/,我正按照以下方式进行编译:gcc -Wall -o signals signals.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>

void child_work(int l);
void create_children(int n, int l);
void parent_work(int k, int p);
int sethandler( void (*f)(int), int sigNo);
void child_handler(int sig);
void parent_handler(int sig);
void sigchld_handler(int sig);
void usage(void);

volatile sig_atomic_t last_signal = 0;

int sethandler( void (*f)(int), int sigNo)
{
    struct sigaction act;
    memset(&act, 0, sizeof(struct sigaction));
    act.sa_handler = f;
    if (-1==sigaction(sigNo, &act, NULL))
        return -1;

    return 0;
}



void sigchld_handler(int sig) {
    pid_t pid;
    for(;;)
    {
        pid=waitpid(0, NULL, WNOHANG);
        if(pid==0) return;
        if(pid<=0)
        {
            if(errno==ECHILD)
            {
                printf("[%d] No more children parent quits.",getpid());
                exit(EXIT_SUCCESS);
            }

            perror("waitpid:");
            exit(EXIT_FAILURE);
        }
    }
}

void child_handler(int sig)
{
    printf("[%d] received signal %d\n", getpid(), sig);
    last_signal = sig;
    if(last_signal==SIGUSR1)
        if(0==kill(0,SIGUSR2))
            printf("[%d] SENDING signal %d\n", getpid(), SIGUSR2);
        else
            perror("kill:");

}

void parent_handler(int sig) {
    printf("[%d] received signal %d\n", getpid(), sig);
    last_signal = sig;
}

void child_work(int t)
{
    int s;
    srand(getpid());
    s=rand()%(t-1)+2;
    struct timespec tt, tn = {s,0};
    for(tt=tn;nanosleep(&tt,&tt);)
    if(EINTR!=errno)
        perror("nanosleep:");



    printf("[%d] dies",getpid());
    exit(EXIT_SUCCESS);
}


void create_children(int n, int t)
{
    while (n-->0)
    {
        switch (fork())
        {
        case 0:
            if(sethandler(child_handler,SIGUSR1))
            {
                perror("Seting child SIGUSR1:");
                exit(EXIT_FAILURE);
            }

            if(sethandler(child_handler,SIGUSR2))
            {
                perror("Seting child SIGUSR2:");
                exit(EXIT_FAILURE);
            }

            child_work(t);
            exit(EXIT_SUCCESS);

        case -1:
            perror("Fork:");
            exit(EXIT_FAILURE);


        }
    }
}

void usage(void){
    fprintf(stderr,"USAGE: signals n t\n");
    fprintf(stderr,"n - number of children > 0\n");
    fprintf(stderr,"t - max lifetime of child process\n");
}

int main(int argc, char** argv)
{
    int n,t;
    //int childcount;
    if(argc!=3)
    {
        usage();
        return EXIT_FAILURE;
    }

    n = atoi(argv[1]);
    t = atoi(argv[2]);

    if (n<=0 || t<=1) {
        usage();
        return EXIT_FAILURE;
    }

    if(sethandler(SIG_IGN,SIGUSR1))
    {
        perror("Seting parent SIGUSR1:");
        exit(EXIT_FAILURE);
    }

    if(sethandler(parent_handler,SIGUSR2))
    {
        perror("Seting parent SIGUSR2:");
        exit(EXIT_FAILURE);
    }

    if(sethandler(sigchld_handler,SIGCHLD))
    {
        perror("Seting parent SIGCHLD:");
        exit(EXIT_FAILURE);
    }

    create_children(n, t);
    struct timespec tt, tn = {1,0};

    while(1)
    {
        for(tt=tn;nanosleep(&tt,&tt);)
        if(EINTR!=errno) perror("nanosleep:");
        if(0==kill(0,SIGUSR1))
            printf("[%d] SENDING signal %d\n", getpid(), SIGUSR1);
        else
            perror("kill:");

    }




    return EXIT_SUCCESS;
}

当我运行它./program 3 3(它产生3个孩子)我得到奇怪的输出,如:

[2835] dies[2836] dies[2834] dies[2836] dies[2836] received signal 10
[2836] received signal 12
[2836] SENDING signal 12
[2835] dies

你可以看到[2835]和[2836]死2次,我只是想知道它为什么会这样?提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

在信号处理函数中使用printf()会导致未定义的行为。 我无法使用Debian 8.3虚拟机重现您的错误。行为取决于操作系统。

Check here Async-signal-safe functions