簡體   English   中英

子信號與父信號之間的並發競爭

[英]Concurrency race between child and parent signals

我在過去的CMU考試中發現了這個問題,但我不知道如何輸出。

基本上,其背后的想法是,有一個父進程阻塞了用戶定義的信號,然后父進程派生了一個子進程。 根據最先運行的流程(也就是贏得比賽),可能會有不同的輸出。 這是考試中要問的問題 (請閱讀)

這是考試的代碼:

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信號分配一個自定義處理程序,並阻塞集合s中的信號。 這些是哪幾行

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

然后父母將運行這條線

    pid = fork();

這將在該過程中創建一個新的子代。

現在有2種情況將決定輸出。 操作系統安排父級或子級先運行。

假設父級先運行。 然后它將執行LINE A(這是kill函數)

並且由於它是父代,因此pid值將是子代的進程ID。 因此它將把USRSIG1發送給孩子,但是由於它被阻止了,它什么也不做

if語句為全局變量i分配一個值。 如果流程是父流程,則i = 2,否則i =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); 父進程將暫停直到收到信號

現在,子進程將運行,並且它將向進程組中的所有進程(包括自身)發送kill(0,SIGUSR1)信號。 但是,由於它被孩子擋住了,所以什么也不會發生。 父母將接收到該信號,它將使我增加1(所以現在i = 3)。 並且它(父對象)將從函數暫停中恢復以打印I的值(為3)並退出。

現在,該子項將從kill函數恢復,並且由於它是子項,因此if語句將不為真(因此,子項中i的值= 3)。 子級從set和pause()中取消阻止信號。

由於沒有其他進程可以向孩子發送信號,因此它將永遠保持暫停狀態,並且僅父進程的輸出為3。 如果我們采用另一種方式(孩子在父母之前跑),則輸出將僅為4。

我感到困惑的是,考試的解決方案說每次運行有2個輸出? 我不知道這怎么可能,因為其中一個過程將停留在pause()中。

解決方案密鑰說,LINE A的可能輸出為:

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

這就是我從這個問題中所能理解的。 任何幫助或提示,將不勝感激。

如果孩子先跑,則輸出將為5,因為它將接收來自其自身和父母的信號。 如果兩個進程都在執行一次kill(pid,USRSIG1)之前都進入pause()都不會終止或打印。

POSIX還允許兩個進程由於延遲的信號而終止並打印(例如,如果使用網絡消息而不是共享內存),並且允許子進程打印任何int值,因為i不是volatile sig_atomic_t類型。

從評論看來,考試作者錯誤地認為pause()將神奇地等待,直到接收到所有已發送或將被發送到流程的信號。

如果sigprocmask(SIG_UNBLOCK, &s, 0); pause(); sigprocmask(SIG_UNBLOCK, &s, 0); pause(); 被替換為sigsuspend的適當調用,它將作為考試作者陳述。 父母會收到1個信號,而孩子會收到1個或2個信號,因為來自父母的信號可能太遲或與自身的信號合並。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM