2016-05-15 7 views
2

以下に例を示します。両方のコヒーレントアルゴリズムが同じオブジェクトを使用して全体的にロックされている間に、なぜキューがロックされているのかわかりません。この例のキューロックが必要な理由

キューロックが必要であると言われています。

using System; 
using System.Threading; 
using System.Collections; 

public class CrudeThreadPool 
{ 
    static readonly int MaxWorkThreads = 4; 
    static readonly int WaitTimeout = 2000; 

    public delegate void WorkDelegate(); 

    public CrudeThreadPool() { 
     stop = false; 
     workLock = new Object(); 
     workQueue = new Queue(); 
     threads = new Thread[ MaxWorkThreads ]; 

     for(int i = 0; i < MaxWorkThreads; ++i) { 
      threads[i] = 
       new Thread(new ThreadStart(this.ThreadFunc)); 
      threads[i].Start(); 
     } 
    } 

    private void ThreadFunc() { 
     lock(workLock) { 
      do { 
       if(!stop) { 
        WorkDelegate workItem = null; 
        if(Monitor.Wait(workLock, WaitTimeout)) { 

         lock(workQueue.SyncRoot) { 
          workItem = 
           (WorkDelegate) workQueue.Dequeue(); 
         } 
         workItem(); 
        } 
       } 
      } while(!stop); 
     } 
    } 

    public void SubmitWorkItem(WorkDelegate item) { 
     lock(workLock) { 
      lock(workQueue.SyncRoot) { 
       workQueue.Enqueue(item); 
      } 

      Monitor.Pulse(workLock); 
     } 
    } 

    public void Shutdown() { 
     stop = true; 
    } 

    private Queue   workQueue; 
    private Object  workLock; 
    private Thread[]  threads; 
    private volatile bool stop; 
} 

public class EntryPoint 
{ 
    static void WorkFunction() { 
     Console.WriteLine("WorkFunction() called on Thread {0}", 
         Thread.CurrentThread.ManagedThreadId); 
    } 

    static void Main() { 
     CrudeThreadPool pool = new CrudeThreadPool(); 
     for(int i = 0; i < 10; ++i) { 
      pool.SubmitWorkItem(
       new CrudeThreadPool.WorkDelegate(
           EntryPoint.WorkFunction)); 
     } 

     Thread.Sleep(1000); 

     pool.Shutdown(); 
    } 
} 

キューをロックする理由はなんですか?

+0

あなたはどこでそのコードを取得しましたか、それはなぜ動作すると思われますか? – Evk

+0

そのコードは間違いなく機能します。それは1つのコースブックから来ます。 –

+1

このコードを複数回実際に実行しようとすると、コードが壊れていることがわかります。あなたは10個のアイテムをキューに入れますが、ランダムな数のアイテムが処理されます。ときどき10、ときには8、時には4、ときには0になります。それを書いた人は自分が何をしているのか理解できませんでした(特にMonitor.PulseとMonitor.Waitの動作)。なぜキューアクセスをロックするのかについて議論する理由はあまりありません。 – Evk

答えて

1

内部ロックは、実際には必要ありません.Waitに再び到達しない限り、ロックは保持され、すべてのプロデューサをブロックします。したがって、これはうまくいくはずです:

private void ThreadFunc() { 
    do { 
     if(!stop) { 
      WorkDelegate workItem = null; 
      lock(workLock) { 
       if(Monitor.Wait(workLock, WaitTimeout)) { 
        workItem = (WorkDelegate) workQueue.Dequeue(); 
       } 
      } 
      if (workItem != null) workItem(); 
     } 
    } while(!stop); 
} 

public void SubmitWorkItem(WorkDelegate item) 
{ 
    lock(workLock) { 
     workQueue.Enqueue(item); 

     Monitor.Pulse(workLock); 
    } 
} 

Joseph Albahari's siteは、スレッドシナリオの素晴らしい参照です。 これは古典的なプロデューサ/コンシューマのシナリオなので、BlockingCollectionを使用することをお勧めします。

+0

これは、キューが空であるという例外をスローします。それだけです。 – Evk

+0

@Evkこれを修正するために非常に真実です。 – Slugart

+0

残念なことに、これは改善されませんでした。現在、キューが空の場合、サイクルを何もせず、CPUリソースを無駄にしてループします。サンプルコードMonitor.WaitとMonitor.Pulseは、シグナリングに使用されます。 – Evk

関連する問題