2013-12-15 58 views
2

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

当孩子分叉时,它现在是父母还是孩子只有以前的父母?

由于包含一个处理程序,因此缺省处理程序无效。那么你能否改变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

回答

1

当一个子进程分叉,这是非常接近的父进程的精确副本。与单线程进程中,有三个主要区别:

  1. 父进程ID是不同
  2. 进程ID是不同的。
  3. fork()返回的值是不同的

(有关其它差异,请参见POSIX手册页fork())。在孩子的信号处理程序是相同的父。但是,孩子可以肯定并独立地更改其任何信号处理程序。

您不能设置信号处理程序来捕捉SIGKILL。这个信号永远不会被发现。

2

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

就其如何影响接收信号的过程而言,

当孩子分叉时,它现在是父母还是孩子只有前父母?

这绝对是它的父母的孩子。它是否成为父母本身取决于它是否分岔了自己的孩子。

由于包含处理函数,因此缺省处理函数无效。那么你能改变一个SIGINT来不终止一个进程吗?

SIGINT的默认处置是终止进程,但您可以捕获并处理SIGINT,或者可以阻止或忽略它。默认处置并非如覆盖一样无效,直到(并且如果)再次更改它。

为什么“SIGKILL received”从不打印?

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

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

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

信号是一个令人困惑的话题,因为洋葱有几层,规则和平台特定的语义有足够的例外,使他们感到沮丧。我从来没有发现能够详尽涵盖它们的单一来源。也就是说,信号处理和处理程序是洋葱的外层,网络上有很多可用的来源可以很好地覆盖这些信息。