この投稿では、開発中のマルチスレッドプログラムの清潔さと安全性の闘いを目的とした一連の記事を続けます。

図1-シグナル変数の参加による第1種の相互ブロッキング。
この投稿の一部として、信号変数を使用するときに発生する問題を調べ、それらを回避する方法を示します。
あなたの許可があれば、 以前の投稿にすでに精通していることを願って、長い紹介をスキップします。
- デッドロックとは何ですか?
- マルチスレッドプログラムの「遷移モデル」の作成方法と読み取り方法。
- ミューテックスの使用時にデッドロックを回避する方法。
そのため、シグナル変数(または条件変数)は同期の手段であり、あるスレッドが特定の条件が別のスレッドによって満たされるまで待機することを可能にします。
マルチスレッドプログラム移行モデルの拡張
ミューテックスのキャプチャとリリースの操作のみで動作するマルチスレッドプログラムを記述する場合、L(ロック)とU(ロック解除)という表記のみが必要でした。 新しい操作で移行モデルを拡張します。
- W(待機、待機)-この操作の原因となったサブジェクト(スレッド)を、対応するシグナル変数からのシグナルのスタンバイ状態にします。 同じシグナル変数の場合、保留スレッドの数に制限はありません。
- E(送信、送信)-シグナル変数によって単一のシグナルを送信します。 シグナルは、待機の合計数に関係なく、待機しているストリームの1つのみを受信できます。どのスレッドが発行操作を実行したかは関係ありません。
- B(ブロードキャスト)-対応するシグナル変数でシグナルを待っているすべてのストリームにシグナルを送信します。どのストリームがブロードキャスト操作を実行したかは関係ありません。
シグナルを受信したストリームが起動し、チェーンに沿ってさらに実行を続けます。 信号を送信する時点で待機中のコンシューマストリームが1つもない場合、信号は単に無視されますが、信号を送信したという事実は記憶されません。 したがって、いずれかのスレッドが操作Wを実行すると、信号が再度送信されるまで待機状態になります。
以前に検討された操作LおよびUから類推できます。操作Wは、ミューテックスLをキャプチャする操作と共通の機能を備えていますが、Lは既にキャプチャされたミューテックスを再キャプチャしようとした場合にのみストリームの実行をブロックし、Wは常にストリームの実行をブロックします。 オペレーションEとBは、ミューテックスUを解放するオペレーションと共通の機能を備えています。したがって、シグナル変数は通常のミューテックスとして表すことができます。
実際には、信号変数は多くの場合、mutexとともに使用されます(たとえば、libpthreadライブラリ内)。 モデルを構築するとき、信号変数の使用と密接にリンクされているミューテックスは、操作W、E、およびBのロジックで考慮されると仮定します。
危険はどこですか?
シグナル変数は、2つのケースのいずれかでデッドロックを引き起こす可能性があります。
K番目のストリームがI番目の信号変数に到着する信号を待機している場合、K番目のストリームがIthの信号送信を(直接または間接的に)ブロックするミューテックスをキャプチャする場合、信号変数は第1種の相互ブロッキングの原因です。他のエンティティからの変数条件(図1)。
K番目のストリームがI番目の信号変数に到着する信号を待機し、この信号を送信できるストリームがKを送信するJ番目の信号変数に到着する信号を待機している場合、 信号変数は第2種の相互ブロッキングの原因です。 thストリーム(図2)。

図2-シグナル変数の関与による第2種の相互ブロッキング。
信号変数を安全に使用するための2つのルール
確立された伝統によれば、上記の状況を回避できるようにする2つのルールを策定します。
ルール1
シグナル変数のソースストリームである各ストリームがシグナル変数のコンシューマストリームでない場合、シグナル変数は第2種のデッドロックを引き起こすことはできません。
シグナル変数のコンシューマストリームを、実行チェーンにこのシグナル変数のシグナル待機の少なくとも1つの操作Wが含まれるストリームと呼びます。
特定の条件変数のソースストリームを、実行チェーンに、この信号変数に沿って信号を送信する操作EまたはBが少なくとも1つ含まれているストリームと呼びましょう。
ルール2
率直に言って、私は2番目のルールを定式化するのにいくつかの困難がありました。 私たちの研究では、プレゼンテーションを簡素化するためにこの投稿のフレームワークで紹介しなかった概念と定義を取り上げました。 起こったことは次のとおりです。
特定のシグナル変数からのシグナルが予想される各スレッドの実行バリアントのダイナミクスについて、すべてのメテットが呼び出し時にこのスレッドによってキャプチャされた場合、シグナル変数は、ミューテックスの安全な使用に関するルールに準拠するマルチスレッドプログラムの最初の種類の相互ブロッキングを引き起こすことはできませんこのシグナル変数は、このシグナル変数のシグナルを送信する少なくとも1つのスレッドのミューテックスとの桁違いの大きな関係に関連付けられていません。
これは、本質的に、呼び出しWでスレッドが「スリープ」するまで、「ウェイクアップ」するためにEまたはBを送信するために必要な単一のミューテックスをキャプチャしなかったことを意味します。
範囲の拡大
結論として、たとえばpthread_cond(libpthreadライブラリ)のように、シグナル変数を一種の言語プリミティブとして排他的に認識してはならないという事実に注目してみましょう。 シグナル変数は、ある条件が別のスレッドによって満たされるまで1つのスレッドで待機することを可能にする機能的な設計です。
このような機能構築の重要な特別なケースは、別のスレッドの完了を待つための待機(または参加)の呼び出しです。 多くの場合、この期待はデッドロックチェーンの参加者ですが、この同期プリミティブを考慮から除外すると、そのようなロックを修復することは不可能になります。 これは、マルチスレッドプログラムの移行モデルを構築する際に考慮する必要があります!
すぐに「画面上」
マルチスレッドプログラミングに関する一連の投稿に関心を寄せてくれた著名なHabrausersに感謝します。 私にとって、これは問題の関連性と私たちの研究の重要性の別の確認です。 これは、より多くの記事を書く力を与えます。 私たちの計画では:
- 「ソフト同期ツール」を使用した「動的ロック」の問題の考慮(非ブロッキングでミューテックスをキャプチャする試み、シグナル変数のシグナルをタイムアウトで待機するなど)。
- 数学的基礎の考察と、以前の記事で提示された論文の証拠。
- オートマトンやペトリネットなど、「遷移モデル」に加えて、マルチスレッドプログラムの代替モデルを検討します。
そして、Habrの視聴者にとって引き続き興味深いものであるならば、さらに多くのことです。 ご関心と関心をお寄せいただきありがとうございます! 安全にプログラムしてください!