1

AutoResetEventクラスとまったく同じように動作する同期クラスが必要ですが、1 つの小さな例外があります。

Set()メソッドの呼び出しでは、待機中のスレッドを 1 つだけではなく、すべて解放する必要があります。

どうすればそのようなクラスを構築できますか? 私は単にアイデアがありませんか?

  • マーティン。
4

5 に答える 5

1

私が非常に興味を持って読んだすべてのあなたの考えと意見に感謝します. ここ Stackoverflow でさらに検索を行ったところ、突然これを見つけました。これはまさに私が探していたものであることが判明しました。必要な 2 つのメソッドだけに削減することで、次のような小さなクラスになりました。

public sealed class Signaller
{
    public void PulseAll()
    {
        lock (_lock)
        {
            Monitor.PulseAll(_lock);
        }
    }

    public bool Wait(TimeSpan maxWaitTime)
    {
        lock (_lock)
        {
            return Monitor.Wait(_lock, maxWaitTime);
        }
    }

    private readonly object _lock = new object();
}

そして、それはまさにそれがすべきことをします! ソリューションがこれほどシンプルであることに驚き、そのシンプルさが大好きです。美しい。ありがとう、マシュー・ワトソン!

  • マーティン。
于 2014-12-14T09:31:37.893 に答える
0

イベントが共通のフィールドまたはプロパティのすべてのスレッドによって参照されている場合、共通のフィールドまたはプロパティを新しい非シグナル イベントに置き換えてから、古いイベントにシグナルを送ることができます。新しい同期オブジェクトを定期的に作成するため、多少のコストはかかりますが、うまくいくでしょう。これが私がそれを行う方法の例です:

public static class Example
{
    private static volatile bool stopRunning;
    private static ReleasingAutoResetEvent myEvent;

    public static void RunExample()
    {
        using (Example.myEvent = new ReleasingAutoResetEvent())
        {
            WaitCallback work = new WaitCallback(WaitThread);

            for (int i = 0; i < 5; ++i)
            {
                ThreadPool.QueueUserWorkItem(work, i.ToString());
            }

            Thread.Sleep(500);

            for (int i = 0; i < 3; ++i)
            {
                Example.myEvent.Set();
                Thread.Sleep(5000);
            }

            Example.stopRunning = true;
            Example.myEvent.Set();
        }
    }

    private static void WaitThread(object state)
    {
        while (!Example.stopRunning)
        {
            Example.myEvent.WaitOne();
            Console.WriteLine("Thread {0} is released!", state);
        }
    }
}

public sealed class ReleasingAutoResetEvent : IDisposable
{
    private volatile ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    public void Set()
    {
        ManualResetEvent eventToSet = this.manualResetEvent;
        this.manualResetEvent = new ManualResetEvent(false);
        eventToSet.Set();
        eventToSet.Dispose();
    }

    public bool WaitOne()
    {
        return this.manualResetEvent.WaitOne();
    }

    public bool WaitOne(int millisecondsTimeout)
    {
        return this.manualResetEvent.WaitOne(millisecondsTimeout);
    }

    public bool WaitOne(TimeSpan timeout)
    {
        return this.manualResetEvent.WaitOne(timeout);
    }

    public void Dispose()
    {
        this.manualResetEvent.Dispose();
    }
}
于 2014-12-13T19:22:29.693 に答える