簡體   English   中英

C中的信號處理——中斷中的中斷

[英]Signal handling in C - interrupt in interrupt

我想知道當我的程序同時處理其他信號時是否有可能被信號中斷,我嘗試用以下方法模擬它:

#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>

void sig_output()
{
    sigset_t set;
    sigprocmask(0,NULL,&set);
    printf("currently blocking:");
    if (sigismember(&set,SIGUSR1))
        printf("\nSIGUSR1");
    if(sigismember(&set,SIGUSR2))
        printf("\nSIGUSR2");
    printf("\n");
    return ;
}

void sig_handler(int sig)
{
    raise(SIGUSR1);    
    printf("start\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end\n");
    return ;
}

void other_sig_handler(int sig)
{  
    printf("start - other\n");
    if (sig==SIGUSR1)
        printf("SIGUSR1\n");
    else if (sig==SIGUSR2)
        printf("SIGUSR2\n");
    printf("end - other\n");
    return ;
}

int main()
{
    sig_output();
    struct sigaction a;
    a.sa_handler=sig_handler;
    a.sa_flags=0;
    sigset_t set,old;
    //blocking SIGUSR1,SIGUSR2
    sigemptyset(&set);
    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    printf("blocking SIGUSR1, SIGUSR2\n");
    sigprocmask(SIG_SETMASK,&set,&old);
    sig_output();
    //adding handles for SIGUSR1,SIGUSR2
    sigemptyset(&(a.sa_mask));
    sigaction(SIGUSR1,&a,NULL);
    a.sa_handler=other_sig_handler;
    sigaction(SIGUSR2,&a,NULL);
    printf("poczatek wysylania \n");
    raise(SIGUSR1);
    raise(SIGUSR2);
    raise(SIGUSR1);
    printf("using sigsuspend\n");
    sigsuspend(&old);
    printf("end of program\n");
    return 0;
}

每次我運行這個程序我都會得到

currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program

總是這樣嗎?

引用sigaction(2)聯機幫助頁:

信號例程通常在導致其調用受阻的信號下執行,但可能還會出現其他信號。 全局信號掩碼定義了當前阻止傳遞到進程的一組信號。 進程的信號掩碼從其父進程的信號掩碼(通常為空)初始化。 它可以通過調用sigprocmask(2)或在向進程傳遞信號時更改。

您可以使用SA_NODEFER標志控制信號是否在其信號處理程序中自動阻塞。

據我所知,傳遞這些特定掛起信號的順序沒有定義。 但是,信號(主要SIGCLD有一個例外,傳統上是通過“作弊”完成的)“非排隊”,實時信號除外。 非排隊方面意味着如果你有信號 X 阻塞,然后raise它提升兩次(就像你上SIGUSR1所做的那樣),你只會得到它傳遞一次。

在至少一個系統 (MacOS) 上記錄的唯一順序是:

If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.

(這些是SIGSEGVSIGBUS之類的東西。)通常,您可以通過使用信號阻塞掩碼來控制傳遞順序:在某個點取消阻塞任何特定信號,這些信號是可以在該點傳遞的.

如果您沒有設置SA_NODEFER ,那么您的處理程序入口處的阻塞掩碼將始終阻塞您的處理程序正在處理的任何信號,這樣您就不必擔心遞歸問題。

SIGCLD的特殊情況來自 System V,它最初通過在每次SIGCLD交付時將處理程序重置為SIG_DFL來實現這一點。 (事實上,SysV 對所有信號都這樣做,無論您是否需要,都有效地實現SA_RESETHAND 。)默認操作是丟棄信號,就好像處理程序是SIG_IGN一樣。 當多個子進程在處理程序可以執行其操作之前完成時,這當然會產生競爭條件。 但是,SysV 人員沒有阻止/取消阻止 model,而是進行了黑客攻擊:在SIGCLD處理程序的末尾,您將調用signal(SIGCLD, handler); 修復處理程序。 那時,如果有任何尚未wait的退出子進程,SysV 將立即生成一個SIGCLD ,並且您的處理程序將遞歸進入。 這使得信號看起來好像在排隊,但實際上並沒有排隊。

有關 Linux 信號的更多信息,請參見(例如) http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html

暫無
暫無

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

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