2016-04-30 9 views
3

私は、マルチスレッドのWebプロキシを実装するための基本的なスケッチを持っている:マルチスレッドシグナルハンドラ内でfflushを呼び出す?

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); 
} 

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

答えて

3

スレッドがストリームデータ構造を保護するmutexをロックする標準IO関数を呼び出したとします。そのmutexのロックを解除する前に、シグナルが送られ、シグナルハンドラが呼び出されます。シグナルハンドラはfflush()を呼び出し、ミューテックスをロックしようとします。あなたのシグナルハンドラはmutexを待つが、シグナルハンドラが戻るまであなたのスレッドはブロックされるので、あなたのスレッドと標準のIOストリームは永遠にデッドロックされます。これは古典的なデッドロックです。

これはスレッドとシグナルハンドラの違いです。あるスレッドがmutexをロックしようとしたときにすでにロックされていると判断すると、スリープ状態になり、他のスレッドが実行され、遅かれ早かれmutexを保持するスレッドがロックを解除します。しかし、あなたのシグナルハンドラはスレッドではないので、スリープ状態にはならず、中断されたスレッドを実行させます - シグナルハンドラが返すまで、そのスレッドは単にブロックします。

+0

私は非同期配信をブロックし、 'sigwait'を呼び出してシグナルを同期的に受信する専用のスレッドを作成する必要がありますか? – user6269144

+1

いいえ、信号ハンドラから非同期セーフではない関数を呼び出さないでください。それは安全ではありません。あなたのシグナルハンドラは、例えば 'volatile sig_atomic_t'として宣言したフラグをセットしてから復帰することができます。フラグがセットされていることを検出すると、スレッドの1つがストリームをフラッシュできます。あるいは、代わりにシグナル以外のメカニズムを使用してください。 –

+0

あなたが書いたことは、mutexで保護されたストリームにのみ適用されます。後者はC11以来標準化されている。 C11標準より前のコードでは、デッドロックは発生しませんでしたが、別のスレッドのハーフフィルドバッファをフラッシュするなど、他の種類の奇妙な動作が発生する可能性があります。 – alk

関連する問題