2015-02-06 110 views
1

我遇到了一個我無法弄清楚的問題。這可能不容易解釋。在線程中啓動作業從其他線程的隊列中讀取

我有這個私有構造一個單例類:

private BarcodeMonitor() 
{ 
    processors[Machines.H1] = new BarcodeProcessor { Queue = new BlockingQueue<BarcodeData>("H1") }; 
    processors[Machines.H2] = new BarcodeProcessor { Queue = new BlockingQueue<BarcodeData>("H2") }; 
    processors[Machines.M] = new BarcodeProcessor { Queue = new BlockingQueue<BarcodeData>("M") }; 
    processors[Machines.HP] = new BarcodeProcessor { Queue = new BlockingQueue<BarcodeData>("HP") }; 

    foreach (KeyValuePair<Machines, BarcodeProcessor> pair in processors) 
    { 
     Thread t = new Thread(t1 => pair.Value.StartProccesingQueue()); 
     t.Name = pair.Key.ToString() + "Processor"; 
     t.Start(); 
     threads.Add(t); 
    } 
} 

一個新的和獨特的BlockingQueue是考慮到BarcodeProcessor,並採取了名字。

BarcodeMonitor具有此方法:

public BlockingQueue<BarcodeData> GetQueue(Machines machine) 
{ 
    var processor = processors[machine]; 
    return processor.Queue; 
} 

使得傳入的條形碼被放在正確的機器的隊列中。這工作正常。

條形碼在StartProccesingQueue()(其中4個實例正在運行)中出列。在出隊方法,我有:

System.Console.WriteLine(string.Format("Thread {0} is taking from queue {1}", Thread.CurrentThread.Name, name)); 

Dequeue()使用Monitor.Wait(_internalQueue)當隊列是空的。 Enqueue()使用Monitor.PulseAll(_internalQueue)繼續等待出隊。

發生什麼情況是StartProccesingQueue()方法從其他隊列中獲取,即使它只是訪問Queue屬性,該屬性被分配了新的BlockingQueue。事實上,到目前爲止,我只看到隊列「M」中的項目被採用,並且只有H1和H2線程正在執行它。

我真的不明白爲什麼會發生這種情況。

+1

您正在訪問閉包中的foreach-iterator變量。這很危險,行爲依賴於編譯器。這可能是原因。只需做一個'var value = pair.Value;'並在lambda中使用,看看是否有幫助。 – Dirk 2015-02-06 12:27:53

+0

@Dirk哇,這樣做。所有這一切都花了我的時間找到答案......作爲接受答案:) – Halfgaar 2015-02-06 12:38:43

+0

它已經被回答了幾次,這只是一個不同的背景。我會發佈一個副本。 – Dirk 2015-02-06 12:39:26

回答

0

嗯,我不太確定,但我認爲當你做pulseAll(_internalQueue)所有等待的線程都被注意到_internalQueue現在已經可以處理,請參閱MSDN PulseAll()。 也許試試只是pulse(_internalQueue)這應該只通知等待此線程的線程_internalQueue,請參閱MSDN pulse()

+0

我確實感到困惑,爲什麼'BlockingQueue'的原作者使用'PulseAll()',但最後,答案與訪問閉包中的foreach變量有關。看到我的問題的第一個評論。 – Halfgaar 2015-02-06 13:31:36