我從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
這是所有我可以從問題的理解。任何幫助或暗示將不勝感激。