2009-06-01 28 views
4

私はLinux上で同時に実行できる何回の同時実行を制御するラッパーを作成しようとしています。これを行うために、私はシステム全体のカウントセマフォを使用しています。セマフォを作成してsem_wait()を実行し、子プロセスを起動して、子プロセスが終了するとsem_post()を実行します。それは結構です。sem_wait()/ sem_post()のシグナル安全な使用

問題は、このラッパーに送信されたシグナルを安全に処理する方法です。シグナルをキャッチしない場合、コマンドはsem_post()を実行せずに終了し、セマフォーカウントが1だけ永久に減少します。そこで、sem_post()を実行するシグナルハンドラを作成しました。しかし、まだ、問題があります。

ハンドラがsem_wait()が実行される前に、信号はsem_wait()なしで発生するsem_post()を引き起こし、sem_wait()完了する前に到着する可能性が取り付けられている場合。シグナルハンドラを設定する前にsem_wait()を実行すると、その逆が可能です。

明らかに次のステップは、ハンドラとsem_wait()の設定中に信号をブロックすることでした。これは私が今持っているものの擬似コードです:

void handler(int sig) 
{ 
    sem_post(sem); 
    exit(1); 
} 

... 
sigprocmask(...); /* Block signals */ 
sigaction(...);  /* Set signal handler */ 
sem_wait(sem); 
sigprocmask(...); /* Unblock signals */ 
RunChild(); 
sem_post(sem); 
exit(0); 

問題は今sem_wait()をブロックすることができますし、その時に、信号がブロックされているということです。プロセスを強制終了しようとするユーザーは、 "kill -9"に頼ることになるかもしれません。これは、何があってもそのケースを処理できないため、私が励ましたくない動作です。 sem_trywait()を短時間使用し、sigpending()をテストすることができましたが、セマフォを待っているプロセスが次に実行される保証がなくなるため、公平性に影響します。

セマフォーの取得中に信号を処理できる本当に安全なソリューションはありますか?私は "セマフォーを持っていますか?"というメッセージに頼ってシグナルブロッキングを取り除くことを検討していますが、これはセマフォーを取得してからグローバルに設定するのが100%安全ではありません。

答えて

6

確信していますか?sem_wait()はシグナルをブロックしますか?私はこれが当てはまるとは思わない。 man page for sem_wait()は、EINTRエラーコードがsem_wait()から返され、信号によって中断されたとします。

このエラーコードを処理できるようになり、信号が受信されるはずです。信号が受信されなかった場合に遭遇しましたか?

sem_wait()が返すことができるエラーコードを処理することを確認します。それはまれであるかもしれませんが、あなたが100%あなたの基地の100%をカバーしたいと確信したいならば。

+0

私が不明な場合は申し訳ありません。sem_wait()はあなたが言うようにシグナルをブロックさせませんが、ブロックするためにsigprocmask()を使用しています。しかし、私はあなたが正しい解決策を持っていると思います。これは、ハンドラが終了せず、 "終了する時間"と言うフラグを設定すべきであることを意味するEINTRエラーコードを調べることです。私はそれをテストします。ありがとう。 – Jeremy

+0

それはうまくいった。私はシグナルのブロックを取り除き、シグナルハンドラーをグローバルな意味を設定するように変更しました。 sem_wait()がエラーを返した場合は、終了してセマフォカウントを保持します。私が子供を待っているなら、私はtimeToQuitをグローバルにテストします。終了する時が来たら、私は子供を殺し、セマフォカウントを保持するsem_post()を行います。ありがとう。それはkill -9を無視してシグナル安全でなければなりません。 – Jeremy

0

問題に正しく近づいていますか?子が終了するのを待つ場合は、waitpid()システムコールを使用することができます。あなたが観察したように、信号を受信する可能性がある場合は、子供がsem_post()を行うと期待するのは信頼できません。この問題への

+0

実際には、子はセマフォを認識しておらず、親は私が表示していない擬似コードのRunChild()関数でwaitpid()を実行しています。その部分はうまくいき、sem_take()が完了した後、子プロセスの終了と親プロセスへのシグナルの送信を処理していました。私は、シグナルハンドラとsem_wait()の設定の間のクリティカルセクションが心配でしたが、sem_wait()エラーコードを確認することは、私が見ることができなかった単純な解決策でした。 – Jeremy

0

私は最も簡単な、これは古いですけど、まだグーグルのこの礼儀を読んで、これらの利益のために...

(とのみを?)堅牢なソリューションは、System Vセマフォを使用することで、どのクライアントがカーネルによって自動的に返される方法でセマフォーリソースを取得できるようにします。プロセスの終了方法はありません。

関連する問題