6

編集:この質問をすることさえ一時的な狂気を認めたいと思いますが、当時は理にかなっていました(以下の編集2を参照)。

.NET 3.5 プロジェクトの場合、2 種類のリソース ( R1R2 ) が利用可能かどうかを確認する必要があります。各リソース タイプは、いつでも (たとえば) 10 個のインスタンスを持つことができます。

いずれかのタイプのリソースが利用可能になったら、ワーカー スレッドを起動する必要があります (スレッドの数は可変です)。以前の実装では、リソースの種類は 1 つしかなく、セマフォを使用して可用性を確認していました。

ここで、リソースの可用性を追跡する 2 つの別個のセマフォ ( S1S2 ) を待機する必要があります。

WaitHandle[] waitHandles = new WaitHandle[] { s1, s2 };
int signalledHandle = WaitHandle.WaitAny(waitHandles);

switch (signalledHandle)
{
    case 0:
        // Do stuff
        s1.Release();
    case 1:
        // Do stuff
        s2.Release();
}

ただし、これには 1 つの問題があります。次の MSDN ドキュメントからWaitAny:

呼び出し中に複数のオブジェクトがシグナル状態になった場合、戻り値は、すべてのシグナル状態のオブジェクトの中で最小のインデックス値を持つシグナル状態のオブジェクトの配列インデックスです。

これは、 を呼び出した後、両方のセマフォ カウントを 1 減らした可能性があることを示唆していWaitAnyます。signalledHandles1 が通知されたことを示すため、リソースR1の使用を開始し、完了したら解放します。ただし、 S2が通知されたかどうかがわからないため、このリソースの可用性カウントはオフになっている可能性があります。これが 10 回発生すると、私のセマフォは永久に「空」になり、リソースR2はまったく使用されなくなります。

これに対処する最善の方法は何ですか?2 つのセマフォを単純なカウンターと AutoResetEvent の使用に切り替えて、いずれかのカウンターが変更されたときに通知する必要がありますか? もっとエレガントなアプローチが欠けていますか?

編集 1:
Ravadre によると、セマフォの 1 つだけが実際に変更されWaitAnyます。彼の例を少し変更するとこれが確認されるようですが、これを指定している公式ドキュメントを教えてくれる人はいますか?

編集 2:
帰り道にこれについて考えていました。その時初めて、これが何の役にも立たないということに気がつきましたWaitAny。この問題はセマフォに限定されるものではなく、ほぼすべてのタイプの同期オブジェクトで発生し、WaitAny実質的に役に立たなくなります。

4

2 に答える 2

5

あなたの問題を正しく理解していれば、あなたの解決策は完全に問題ないと思います.msdnの引用を解釈しすぎているだけです. 呼び出すWaitHandle.WaitAny()と、最も低いインデックスが取得されますが、1 つの waitHandle (この場合はセマフォ) のみがロックされます。次のサンプル コードを確認してください。


Semaphore s1 = new Semaphore(1, 2);
Semaphore s2 = new Semaphore(1, 2);

WaitHandle[] handles = new WaitHandle[] { s1, s2 };

int x = WaitHandle.WaitAny(handles);

int prevS1 = s1.Release();
int prevS2 = s2.Release();

このシナリオでprevS1は、セマフォs1が「待機していた」ため、0 に等しくなり、カウンターは 0 に減少しますが、prevS2インスタンス化されてから状態が変化していないため、1 に等しくなります (Release()メソッドは前にカウンターを返します)。したがって、1 を返すことは「1 だったのに 2 になった」ことを意味します)。

見たい別のリソース: http://www.albahari.com/threading/part2.aspx#_Wait_Handles。「公式」のソースではありませんが、信頼できないと判断する理由はないと思います。

于 2009-08-19T14:22:48.470 に答える