4

C++11 で、リクエスト ループのタイプ (Web リクエスト ループの一部として) が与えられた場合に、キャッチされたシグナルに対して安全でないコードを実行する最も安全な (そして最も効率的な) 方法は何ですか? たとえば、Linux コマンド ラインから SIGUSR1 をキャッチすると、次のようになります。kill -30 <process pid>

次に発生するリクエストで「安全でないコード」が実行されることは許容されます。安全でないコードが実行される前にシグナルが複数回発生しても、情報は失われません。

たとえば、私の現在のコードは次のとおりです。

static bool globalFlag = false;

void signalHandler(int sig_num, siginfo_t * info, void * context) {
    globalFlag = true;
}
void doUnsafeThings() {
    // thigns like std::vector push_back, new char[1024], set global vars, etc.
}
void doRegularThings() {
    // read filesystem, read global variables, etc.
}

void main(void) {

    // set up signal handler (for SIGUSR1) ...
    struct sigaction sigact;
    sigact.sa_sigaction = onSyncSignal;
    sigact.sa_flags = SA_RESTART | SA_SIGINFO;
    sigaction(SIGUSR1, &sigact, (struct sigaction *)NULL);

    // main loop ...
    while(acceptMoreRequests()) { // blocks until new request received
        if (globalFlag) {
            globalFlag = false;
            doUnsafeThings();
        }
        doRegularThings();
    }
}

メインループのテスト+ globalFlagブール値の設定に問題がある可能性があることを私は知っています。

編集:if (globalFlag)テストはかなりタイトなループで実行され、「時折の」偽陰性は許容されます。しかし、とにかく Basile Starynkevitch のソリューションには最適化がないと思いますか?

4

1 に答える 1

9

旗を宣言する必要があります

  static volatile sig_atomic_t globalFlag = 0;

たとえばsig_atomic_tこの質問 を参照し、修飾子を忘れないでくださいvolatilesigatomic_t( C の綴りかもしれません)。

Linux (具体的には) では、signalfd(2)を使用してシグナルのファイル記述子を取得できます。その fd は、イベント ループによってpoll(2) -ed にすることができます。

一部のイベント ループ ライブラリ ( libeventlibev ...) は、シグナルの処理方法を認識しています。

また、初期化時にパイプを設定し (詳細についてはpipe(2)pipe(7)を参照) 、シグナル ハンドラでそのパイプの一部を write(2)するというトリックもあります。イベント ループは、そのパイプをポーリングして読み取ります。このようなトリックはQt によって推奨されています。

signal(7)およびsignal-safety(7)も参照してください(シグナル ハンドラ内で使用できる機能またはシステム コールの制限されたセットについて説明しています)。

ところで、正確さは効率よりも重要です。一般に、シグナルはほとんど得られません (たとえば、ほとんどのプログラムは、ミリ秒ごとではなく、せいぜい 1 秒ごとにシグナルを受け取ります)。

于 2013-09-20T01:20:20.343 に答える