きっかけは
マルチスレッド(プロセス)プログラミングモデルに触れたことから始まり、学んだのはセマフォ(Semaphore)に関する同期プリミティブでした。なぜ .Net Framework に対応するものが存在しないのかわかりません。恐ろしいのは、私が彼女を利用して実績のある C++ コードを多数実装したことです。革命の殉教者たちが無駄に薬を飲んで出血するのを防ぐために、私は自分で子供を産まなければなりませんでした。
セマフォとは何ですか?
セマフォの概念をすでに理解している場合は、このセクションを飛ばしてください。
セマフォは、マルチスレッド環境で使用される機能であり、さまざまなスレッドがパブリック リソースを正しく合理的に使用できるように調整する役割を果たします。
駐車場の仕組みを見てみましょう。話を簡単にするために、駐車場には 3 台の駐車スペースしかなく、最初は 3 台の駐車スペースすべてが空いていると仮定します。これは、5台の車が同時に来て、門番がそのうちの3台の進入を妨げずに車止めを下ろした場合、残りの車は入り口で待たなければならず、後続の車も入り口で待たなければならないというものです。入り口。このとき、一台の車が駐車場から出ていきました。それを知った門番は、車両遮断機を開けて一台の車を駐車場に入れました。さらに二台の車が出発したら、さらに二台の車を入れることができました。
この駐車場システムでは、駐車スペースは公共リソースであり、各車は糸のようなもので、ゲートキーパーは信号機として機能します。
さらに、セマフォの特徴は次のとおりです。セマフォは非負の整数(駐車場の数)であり、これを通過するすべてのスレッド(車両)は整数を 1 つ減ります(当然、これを通過するのはリソースを使用するためです)。 )。整数値がゼロの場合、それを渡そうとするすべてのスレッドは待機状態になります。セマフォに対して Wait と Release という 2 つの操作を定義します。 スレッドが Wait オペレーションを呼び出すと、セマフォを渡して 1 つデクリメントするか、セマフォが 1 より大きくなるかタイムアウトになるまで待機します。リリースは実際にセマフォに対して追加操作を実行します。これは、車両が駐車場から出ることに対応します。この操作が「リリース」と呼ばれる理由は、追加操作が実際にセマフォによって保護されているリソースを解放するためです。
成し遂げる
ご存知のとおり、.Net Framework クラス ライブラリで提供されるスレッド同期機能には、
Monitor、AutoResetEvent、ManualResetEvent、Mutex、ReadWriteLock、および InterLock が含まれます。 このうち、AutoResetEvent、ManualResetEvent、および Mutex は WaitHandler から派生しており、実際にはオペレーティング システムによって提供されるカーネル オブジェクトをカプセル化します。その他は .Net 仮想マシンにネイティブである必要があります。明らかに、オペレーティング システムのカーネル オブジェクトの機能は使用効率が低くなります。ただし、ここでは効率は考慮する必要がある問題ではありません。2 つの Monitor と 1 つの ManualResetEvent オブジェクトを使用してセマフォをシミュレートします。
コードは次のとおりです。
パブリッククラスセマフォ
{
private ManualResetEvent waitEvent = new ManualResetEvent(false);
プライベートオブジェクト syncObjWait = new object();
private int maxCount = 1; リソースの最大数
private int currentCount = 0 //現在のリソース数
public Semaphore()
{
}
パブリック セマフォ( int maxCount )
{
this.maxCount = maxCount;
public bool Wait(
)
{
lock( syncObjWait ) //次のコードを入力できるのは 1 つのスレッドだけです
{
bool waitResult = this.waitEvent.WaitOne(); // ここで待機しているリソースの数は 0 より大きいです
if(待機結果)
{
ロック(これ)
{
if( currentCount > 0 )
{
現在のカウント--;
if( currentCount == 0 )
{
this.waitEvent.Reset();
}
}
それ以外
{
System.Diagnostics.Debug.Assert( false, "セマフォでは現在のカウント < 0 は許可されていません" );
}
}
}
waitResult を返します。
}
}
/**//// <概要>
/// タイムアウト復帰を許可する待機操作
/// </概要>
/// <param name="ミリ秒タイムアウト"></param>
/// <戻り値></戻り値>
public bool Wait(int ミリ秒タイムアウト)
{
lock( syncObjWait ) // モニターは、スコープ クラス コードがクリティカル セクション内にあることを確認します。
{
bool waitResult = this.waitEvent.WaitOne(ミリ秒タイムアウト,false);
if(待機結果)
{
ロック(これ)
{
if( currentCount > 0 )
{
現在のカウント--;
if( currentCount == 0 )
{
this.waitEvent.Reset();
}
}
それ以外
{
System.Diagnostics.Debug.Assert( false, "セマフォでは現在のカウント < 0 は許可されていません" );
}
}
}
waitResult を返します。
}
}
public bool Release()
{
lock( this ) // モニターは、スコープ クラス コードがクリティカル セクション内にあることを確認します。
{
currentCount++;
if( currentCount > this.maxCount )
{
currentCount = this.maxCount;
false を返します。
}
this.waitEvent.Set(); //Wait を呼び出すスレッドの参加を許可します。
}
true を返します。
}
}