5

私のプログラムが同時に他の信号を処理しているときに信号によって中断される可能性があるかどうか疑問に思っていたので、次のようにシミュレートしようとしました。

#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

いつもそうですか?

4

2 に答える 2

6

マンページの引用sigaction(2)

シグナルルーチンは通常、呼び出しをブロックしたシグナルで実行されますが、他のシグナルがまだ発生している可能性があります。グローバルシグナルマスクは、プロセスへの配信が現在ブロックされているシグナルのセットを定義します。プロセスのシグナルマスクは、その親のシグナルマスク(通常は空)から初期化されます。sigprocmask(2)呼び出しによって、またはシグナルがプロセスに配信されたときに変更される場合があります。

SA_NODEFERフラグを使用して、シグナルハンドラーでシグナルを自動的にブロックするかどうかを制御できます。

于 2012-04-10T18:07:52.197 に答える
6

これらの特定の保留中のシグナルが配信される順序は、私が知る限り、定義されていません。ただし、リアルタイムのシグナルを除いて、シグナル(ほとんどの場合、「不正行為」によって伝統的に行われる例外があります)「非キューイング」です。SIGCLD非キューイングの側面は、シグナルXがブロックされ、その後raise2回(上記のようにSIGUSR1)ブロックされた場合、1回だけ配信されることを意味します。

少なくとも1つのシステム(MacOS)で文書化されている唯一の注文は次のとおりです。

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

(これらはとのようなものSIGSEGVですSIGBUS。)一般に、信号ブロックマスクを使用して配信の順序を制御できます。ある時点で特定の信号のブロックを解除すると、その時点で配信できる信号になります。

を設定しない場合SA_NODEFER、ハンドラーのエントリのブロックマスクは、ハンドラーが処理している信号を常にブロックするため、再帰について心配する必要はありません。

の特殊なケースはSIGCLDSystemVからのもので、元々は配信SIG_DFLごとにハンドラーをリセットすることでこれを実装していましたSIGCLD。(実際、SysVはすべてのシグナルでこれを実行し、SA_RESETHAND必要かどうかを効果的に実装しました。)デフォルトのアクションは、ハンドラーがであるかのようにシグナルを破棄することでしたSIG_IGN。もちろん、これにより、ハンドラーが処理を実行する前に複数の子プロセスが終了したときに競合状態が発生しました。ただし、ブロック/ブロック解除モデルの代わりに、SysVの人々はハックを入れました。ハンドラーの最後で、ハンドラーを修正するためにSIGCLD呼び出します。signal(SIGCLD, handler);その時点で、まだ-edされていない終了した子がいた場合wait、SysVはすぐに新しい子を生成します。 SIGCLD、およびハンドラーは再帰的に入力されます。これにより、信号が実際にキューに入れられることなく、信号がキューに入れられているように見えました。

Linuxシグナルの詳細については、(例)http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.htmlを参照してください。

于 2012-04-10T18:18:44.983 に答える