3

マルチスレッド Web プロキシを実装するための基本的なスケッチがあります。

FILE *proxy_log_file;

static void
SIGUSR1_handler(int sig)
{
    (void)sig;
    fflush(proxy_log_file);
}

int
main(int argc, char **argv)
{
    proxy_log_file = fopen("proxy.log", "a");
    Signal(SIGUSR1, SIGUSR1_handler);
}

killこれは、ネットワーク管理者がコマンドを使用SIGUSR1して Web プロキシに信号を送信することにより、バッファリングされたログ エントリをログ ファイルにフラッシュできるというものです。fflushただし、シグナル ハンドラ内で呼び出すのが良い考えかどうかはわかりません。スレッドセーフであることは知っfflushていますが、非同期シグナルセーフだとは思いません。fflushマルチスレッドのシグナルハンドラ内で呼び出しを行うと、どのような並行性の問題が発生する可能性がありますか?

4

1 に答える 1

3

ストリーム データ構造を保護するミューテックスをロックする標準 IO 関数をスレッドが呼び出すとします。そのミューテックスのロックを解除する前に、シグナルが配信され、シグナル ハンドラーが呼び出されます。シグナル ハンドラがfflush()ミューテックスを呼び出してロックしようとします。スレッドと標準 IO ストリームは、シグナル ハンドラーがミューテックスを待機するため、永久にデッドロックされますが、シグナル ハンドラーが戻るまでスレッドがブロックされるため、ミューテックスが使用可能になることはありません。典型的なデッドロックです。

これが、スレッドとシグナル ハンドラの違いです。スレッドがミューテックスをロックしようとして、すでにロックされていることがわかった場合、スレッドはスリープ状態になり、他のスレッドが実行され、遅かれ早かれミューテックスを保持しているスレッドがロックを解除します。しかし、あなたのシグナルハンドラーはスレッドではないので、スリープ状態にならず、中断されたスレッドを実行させません.そのスレッドは、シグナルハンドラーが戻るまで単純にブロックされますが、上記の例では決してブロックされません.

于 2016-04-30T19:22:00.427 に答える