如何使用带信号的叉子?

时间:2013-12-15 04:32:16

标签: c signals fork

我不确定更复杂的信号和分叉问题。来自孩子或父母的信号呼叫之间有区别吗?

当孩子分叉时,它现在是父母而只是前一个父母的孩子吗?

由于包含处理程序,默认处理程序无效。那么您可以将SIGINT更改为不终止进程吗?

int count = 0;

void killhandler(int sig){
    printf("SIGKILL received\n");
    return;
}

void childhandler(int sig){
    int status;
    wait(&status);
    count += WEXITSTATUS(status);
    return;
}

main(){
    int i; // for loop iterator
    pid_t pid[3]; // pids of child processes
    Signal(SIGKILL, killhandler);
    Signal(SIGCHLD, childhandler);
    // Fork 3 child processes
    for(i=0; i<3; i++){
        pid[i] = fork();
        if(!pid[i]){ // If child process
            Signal(SIGKILL, SIG_DFL);
            exit(5);
        }
    }

    // Parent process only
    for(i=0; i<3; i++){
        kill(pid[i], SIGKILL);
    }
    sleep(5);
    printf("count = %d\n", count);

    exit(0);
}

为什么"SIGKILL received"从未打印过?

为什么只计算:0,5,10,15

2 个答案:

答案 0 :(得分:3)

  

来自孩子或父母的信号呼叫之间有区别吗?

就如何影响接收信号的过程而言,没有。

  

当孩子分叉时,它现在是父母而只是前一个父母的孩子吗?

它绝对是其父母的孩子。它是否成为父母本身取决于它是否要求自己的孩子。

  

由于包含处理程序,默认处理程序无效。那么你可以改变SIGINT以不终止进程吗?

SIGINT的默认处置是终止进程,但您可以捕获并处理SIGINT,也可以阻止或忽略它。

,默认处置与覆盖无关,直到(以及如果)再次更改为止
  

为什么“SIGKILL收到”从未打印过?

您无法阻止,忽略或捕获SIGKILL。你不会看到你的处理程序打印任何东西,因为它永远不会被调用SIGKILL。 SIGSTOP同样不能被忽略,阻止或处理。在这方面,这是两个特殊信号。

在你的程序中,你试图将SIGKILL设置为默认值,实际上它只是 ,在子节点中处置。由于您的孩子立即退出,父母的信号可能永远不会被传递,因为孩子已经死了,父母的kill可能会因ESRCH失败,例如没有那个带有那个pid的孩子了。 sleep会有帮助,所以他们可以活得足够长,可以被杀死。 (一定要喜欢这个术语。)

您使用WEXITSTATUS是错误的。如果你的意图是计算出自己的意志退出而不是被杀的孩子的数量,你可能只想要一个使用WIFEXITED或WIFSIGNALED的简单计数器。 WEXITSTATUS返回自己退出的子项的状态代码。它可能是0或1或50或75.将它添加到变量可能不是你想要的。

信号是一个令人困惑的主题,因为洋葱有几个层,并且规则和平台特定语义有足够的例外以使它们令人沮丧。我从来没有找到一个涵盖它们的单一来源。也就是说,信号配置和处理程序是洋葱的外层,网上有很多可用的资源,非常好。

答案 1 :(得分:2)

分叉子进程时,它非常接近父进程的精确副本。对于单线程进程,有三个主要区别:

  1. 父进程ID不同
  2. 进程ID不同。
  3. fork()的返回值不同
  4. (有关其他差异,请参阅fork()的POSIX手册页。)子项中的信号处理程序与父项中的信号处理程序相同。但是,孩子当然可以独立地改变其任何信号处理程序。

    您无法设置信号处理程序来捕获SIGKILL。这个信号永远不会被抓住。