2017-10-14 74 views
2

我从CMU过去的考试中发现了这个问题,我无法得到输出是如何可能的。孩子和父母信号之间的并发竞争

基本上,它背后的想法是,有一个父进程阻止用户定义的信号,然后父母分岔一个孩子。并且基于哪个进程首先运行(又名:赢得比赛),则可能有不同的输出。 Here is the question that is being asked in the exam(请阅读)

,这里是从考试代码:

int i = 1; 
void handler (int sig) { 
    i++; 
} 
int main() { 
    pid_t pid; 
    sigset_t s; 
    sigemptyset(&s); 
    sigaddset(&s, SIGUSR1); 
    signal(SIGUSR1, handler); 
    sigprocmask(SIG_BLOCK, &s, 0); 
    pid = fork(); 
     <LINE A> 
    if (pid != 0) { 
     i = 2; 
     <LINE B> 
    } else { 
     i = 3; 
     <LINE C> 
    } 
    sigprocmask(SIG_UNBLOCK, &s, 0); 
    pause(); /* pause to allow all signals to arrive */ 
    printf("%d\n", i); 
    exit(0); 
} 

有3种情况需要进行测试,因为我们需要把功能:

kill(pid,USRSIG1); 

在LINE A或LINE B或LINE C中找到可能的输出。

现在,这里是我做的,我把功能LINE A.

比方说,我们运行程序,那么家长会创建一个空的集合S,信号SIGSUR1添加到它,那么它将为SIGUSR1信号分配一个自定义处理程序,并阻止该集合中的信号。这是这些线路

sigset_t s; 
    sigemptyset(&s); 
    sigaddset(&s, SIGUSR1); 
    signal(SIGUSR1, handler); 
    sigprocmask(SIG_BLOCK, &s, 0); 

然后上级将运行线

pid = fork(); 

将从过程创建一个新的孩子。

现在有两种情况将确定输出。操作系统安排父母或孩子首先运行。

比方说,父母先跑。然后它将执行LINE A(这是kill函数)

并且由于它是父级,所以pid值将是子级的进程ID。所以它会发送USRSIG1给孩子,但是由于它被阻塞,它什么都不会做

if语句为全局变量i分配一个值。如果这个过程是父母的话,我= 2,否则的话,我= 3,所以在我们的父进程中,我们将有I = 2

if (pid != 0) { //if i am a parent then i = 2 
     i = 2; 
     <LINE B> 
    } else { //if i am a child then i = 3 
     i = 3; 
     <LINE C> 
    } 

下一行会在父被执行,它会解锁在SIGUSR1信号 sigprocmask(SIG_UNBLOCK, &s, 0); 与父进程将暂停,直到它接收到的信号

现在孩子会跑,它会包括自己的过程组中的杀(0,SIGUSR1)信号发送给所有的进程。但是由于它在孩子身上受到阻碍,什么都不会发生。父母会收到信号,它会使我增加1(所以现在我在父母中= 3)。并且它将从函数暂停中恢复,以打印I(它是3)的值并退出。

孩子现在从kill函数恢复,因为它是一个孩子,if语句不会是真的(所以我的孩子的值= 3)。孩子解除设置和暂停()的信号。

由于没有其他进程向小孩发送信号,它将永远保持暂停状态,并且仅由父级输出3。如果我们按照其他方式(孩子在父母之前跑步),那么输出将仅为4。

什么令我困惑的是,考试的解决方案说每次运行有2个输出?我不明白这是怎么可能的,因为其中一个进程将停留在()。

该解决方案的关键认为,对于A线的可能的输出是:

3 4, 4 3, 3 5, or 5 3 

这是所有我可以从问题的理解。任何帮助或暗示将不胜感激。

回答

0

如果孩子先跑步,输出将是5,因为它会接收来自自身和父母的信号。如果两个进程在输入pause()之前完成kill(pid,USRSIG1),则两个进程都不会终止或打印。

POSIX还允许两个进程终止并打印由于到延迟信号(例如,如果网络消息来代替共享存储器)和为孩子打印任何int值作为ivolatile sig_atomic_t类型不是。

从评论中可以看出,考试作者错误地认为pause()会奇迹般地等待,直到收到所有发送或将发送给过程的信号。

如果sigprocmask(SIG_UNBLOCK, &s, 0); pause();被替换为sigsuspend的适当调用,它将充当考试作者状态。父母会收到1个信号,孩子会收到1或2个信号,因为来自父母的信号可能太迟或与自己的信号结合在一起。