4

私の以前の質問で、モニターを使用する場合と比較して、C# ではセマフォを使用する方がコストがかかると誰かが言っていた。このコードのセマフォをモニターに置き換えるにはどうすればよいですか?

(別のスレッドで) function2 が完了した後に function1 がその値を返す必要があります。Semaphore.WaitOneをaMonitor.Waitに、Semaphore.Releaseをaに置き換えましたMonitor.PulseAllが、プログラムがハングするPulseAll前にトリガーされていました。Waitその競合状態を回避する方法はありますか?

Semaphore semaphore = new Semaphore(0,1);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    semaphore.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    semaphore.Release();
}
4

2 に答える 2

8

これは、セマフォの代わりに WaitHandle を使用して行うことができます。これは最も単純な代替手段であり、セマフォよりも優れたパフォーマンスを発揮します。

ManualResetEvent manualResetEvent = new ManualResetEvent(false);
byte b;
public byte Function1()
{
    // new thread starting in Function2;

    manualResetEvent.WaitOne();
    return b;
}

public void Function2()
{
    // do some thing
    b = 0;
    manualResetEvent.Set();
}
于 2010-04-02T17:59:54.573 に答える
2

複数のスレッドを待つ必要がある場合、@Reed はエレガントなソリューションを提供しました。

これを使用したくない場合がありますMonitor。@Reed指摘したように、イベントは十分であり、コードの要件に一致する最もクリーンで最も理解しやすいソリューションを提供します。
実際のオペレーティングシステムの同期プリミティブを使用するオーバーヘッドは、おそらくあなたのケースでは問題にならないでしょう.egを使用してもMonitor、はるかに複雑になるという犠牲を払って利益が減少するだけです。

そうは言っても、これはMonitorシグナリングを使用した実装です。

ロックで保護されたフラグを使用しboolて、終了したことを示し、その場合の待機を回避できます。(A)コメントが示す場所
内で新しいスレッドを実際に開始し、と の両方を使用する場合、フラグはまったく必要ありません。(ロ)Function2()lock() WaitOne()Release()

A、フラグを使用する:

class Program
{
    static object syncRoot = new object();
    //lock implies a membar, no need for volatile here.
    static bool finished = false;
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            //Wait only if F2 has not finished yet.
            if (!finished)
            {
                Monitor.Wait(syncRoot);
            }
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        lock (syncRoot)
        {
            finished = true;
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        new Thread(Function2).Start();
        Console.WriteLine(Function1());
    }
}

B、次からスレッドを開始Function1:

class Program
{

    static object syncRoot = new object();
    static byte b;

    public static byte Function1()
    {
        lock (syncRoot)
        {
            // new thread starting in Function2;
            new Thread(Function2).Start();
            Monitor.Wait(syncRoot);
        }
        return b;
    }

    static public void Function2()
    {
        // do some thing
        b = 1;
        //We need to take the lock here as well
        lock (syncRoot)
        {
            Monitor.Pulse(syncRoot);
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(Function1());
    }
}
于 2010-04-02T18:57:34.987 に答える