1

シグナルハンドラーの使用でこの問題が発生します。共有メモリを定義する親プロセスがあります。特定のタイプのシグナル用のシグナルハンドラーを持つ2つの子プロセスをフォークします。これで、子プロセスがその特定のシグナルを受信するたびに、それらのシグナルハンドラーがそのシグナルを処理します。

ここで必要なのは、シグナルハンドラーによってシグナルが処理される回数を追跡することです。その共有メモリを使用して、いずれかの子プロセスによってシグナルが処理される回数だけカウンターをインクリメントする必要があります

そのためには、セマフォを使用する必要があるかもしれません。しかし、私の質問は、シグナルがハンドラーによって処理されるときはいつでも、共有メモリがアクセスされているかどうかをチェックする必要があり、アクセスされている場合はカウンターをインクリメントできないため、ブロックする必要があるかもしれません。シグナルハンドラーでブロックできるとは思いません。

それで、これを達成するための最良の方法は何ですか。私の子プロセスは両方とも、タイプ1のシグナルを処理するために同じシグナルハンドラーを登録します。したがって、その特定のシグナルが受信されるたびに、同じシグナルハンドラールーチンの両方がカウンターをインクリメントしようとします。

これを達成する方法は?

4

1 に答える 1

0

シグナルハンドラでブロックできます。つまり、他のプロセスが実行していることを安全にブロックできるということです。異常なデッドロックの可能性は、独自のプロセスにあります。プロセス内の特定のスレッドがミューテックス (またはセマフォ) をロックしている場合、カーネルはそのスレッドをハイジャックしてシグナルを処理し、ロックを待ちます: デッドロック。スレッドのメイン スタックは、シグナル ハンドラが終了するまでロックを解放しません。シグナル ハンドラは、メイン スタックがロックを解放するまで終了しません。

(同じ自己デッドロックの問題は、mallocのようなあらゆる種類の一般的な呼び出しに隠されています。そのため、「シグナルセーフ」であることが保証されているライブラリ関数の非常に短いリストがあります。)

これを解決するにはいくつかの方法があります。

  • ロックされているスレッドからシグナル ハンドラーを実行できないようにします。を使用してこれを実現するには、少なくとも 3 つの方法がありますpthread_sigmask
    1. ロックを取得する前にそのスレッドのシグナルを一時的にマスクし、ロックの解放後にマスクを解除できます。もちろん、追加のシステム コールにはいくらかコストがかかるため、これがパフォーマンスに敏感なコードである場合は、このアプローチを避けた方がよいでしょう。
    2. すべてのスレッドで永続的にマスクし、sigwait一部のスレッドからのループを使用して、従来のシグナルハンドラーをまったく使用せずにシグナルを処理できます。これにより、「シグナルセーフ」機能などに関するすべての心配から解放されます。
    3. そのスレッドでそれを永続的にマスクし、他の「実際の」作業を行うか、単にsigsuspendループするかのいずれかで、従来のシグナルハンドラーで実行する他のスレッドを作成できます。
  • アトミックを使用します。これが単純なカウンターの場合は、完全にロックすることを回避できます。シグナル ハンドラはメイン スレッドを待機しません。メイン スレッドにも特に問題はありません。シグナル ハンドラがその間に実行されたため、比較とスワップ ループが余分な反復を実行する可能性がありますが、これは実際には問題ではありません。ただし、 C++11 アトミックが共有メモリ領域で正しく動作することが保証されているかどうかは完全にはわかりません。プラットフォームの実装を調べる必要がある場合があります。共有メモリセグメントを使用する他のスレッドと他のプロセスを気にする理由を頭の中で考えることはできませんが、過大な約束はしたくありません。
于 2013-01-17T18:39:10.970 に答える