14

私は3つのスレッド、2つの「ワーカー」と1つの「マネージャー」を持っています。「Workers」スレッドEventWaitHandleは、「manager」スレッドがEventWaitHandleその後、カウンターを増やすように通知するのを待ちます。これらの「ワーカー」スレッドの唯一の違いは、一方がを使用EventWaitHandle.WaitAny()し、もう一方がを使用することEventWaitHandle.WaitOne()です。

コードは次のとおりです。

class Program
{
    static void Main(string[] args)
    {
        MultiThreadedJobs multyThreadedJobs = new MultiThreadedJobs();
        multyThreadedJobs.Start();

        Console.ReadLine();

        multyThreadedJobs.Stop();
    }
}

class MultiThreadedJobs : IDisposable
{
    private EventWaitHandle syncEvent;
    private EventWaitHandle[] syncEventsArray;

    private Thread managerThread;
    private Thread firstWorkerThread;
    private Thread secondWorkerThread;

    private volatile bool running = false;


    public MultiThreadedJobs() // Ctor
    {
        syncEvent = new EventWaitHandle(false, EventResetMode.AutoReset, "JobsSyncEvent");

        syncEventsArray = new EventWaitHandle[1];
        syncEventsArray[0] = syncEvent;

        managerThread = new Thread(ManagerThreadMethod);
        firstWorkerThread = new Thread(FirstWorkerThreadMethod);
        secondWorkerThread = new Thread(SecondWorkerThreadMethod);
    }

    public void Start()
    {
        running = true;

        managerThread.Start();
        firstWorkerThread.Start();
        secondWorkerThread.Start();
    }

    public void Stop()
    {
        running = false;
    }

    private void ManagerThreadMethod() // Manager Thread
    {
        while (running)
        {
            Thread.Sleep(1000);
            syncEvent.Set();
        }
    }

    private void FirstWorkerThreadMethod() // Worker Thread
    {
        int counter = 0;
        while (running)
        {
            syncEvent.WaitOne();
            counter++;
        }
    }

    private void SecondWorkerThreadMethod() // Worker Thread
    {
        int counter = 0;
        while (running)
        {
            EventWaitHandle.WaitAny(syncEventsArray);
            counter++;
        }
    }

    public void Dispose()
    {
        syncEvent.Close();
    }
}

問題は、EventWaitHandle.WaitAny()常にイベントをキャッチする2番目のワーカースレッドだけで、最初のワーカースレッドが不足していることです。それらのそれぞれに約50/50パーセントの代わりに。

4

2 に答える 2

13

ソフトウェアエンジニアリングで非常に一般的な問題である生産者/消費者問題の解決策を探しています。リンクされたウィキペディアの記事には、特にそれを間違った方法で行う方法を示す、まともな背景情報があります。

あなたは確かに間違った方法で解決策を追求しています。AutoResetEventは単純すぎます。あなたはすでにそれに関する1つの問題を見つけました、それは公平さを提供しません。それに関する他の多くの問題、特にプロデューサースレッドがコンシューマースレッドよりも速くジョブを生成する場合、厄介なスレッド競合に悩まされます。

サンプルコードは人工的すぎて、適切な代替手段を提供できません。低レベルのロックは、ReaderWriterLock/Slimクラスによって実装できます。生産者/消費者問題の解決に特に適したクラスは、.NET4BlockingCollectionクラスです。任意の数のプロデューサースレッドとコンシューマースレッドをサポートし、コンシューマーがプロデューサーに追いつけないときにプログラムが爆発しないようにスロットルを提供します。プロデューサーからコンシューマースレッドに渡す偽の「トークン」を使用して、サンプルを書き直すことができます。ABlockingColletion<bool>は仕事を成し遂げます。

于 2013-02-10T13:55:32.497 に答える
6

WaitHandleクラスを使用すると、クライアントは非同期呼び出しを行って、単一のXML Webサービス(WaitHandle.WaitOne)、多くのXML Webサービスの最初のサービス(WaitHandle.WaitAny)、または多くのXML Webサービスのすべて(WaitHandle)を待機できます。 WaitAll)結果を返します。結果が到着したときに処理する場合は、 WaitHandle.WaitAnyメソッドを使用できます。このメソッドは、操作の1つが完了したことを示し、完了した操作を識別します。

どちらの方法も無効にできます。また、渡されたパラメータに応じて、実装は異なります。たとえば、WaitHandle.WaitAnyメソッド(WaitHandle []、Int32、ブール値)は、32ビットの符号付き整数を使用して、指定された配列内の要素が信号を受信するのを待機します。時間間隔を測定し、待機する前に同期ドメインを終了するかどうかを指定します。

WaitHandle.WaitOneメソッド(Int32、ブール値)は、派生クラスでオーバーライドされると、現在のWaitHandleが信号を受信するまで現在のスレッドをブロックし、32ビットの符号付き整数を使用して時間間隔を測定し、待機前に同期ドメインを終了するかどうかを指定します。

于 2013-02-13T07:14:47.097 に答える