2012-04-27 22 views
0

因此,我有一個線程處理數據並放入隊列,然後另一個線程將信息取出並對其執行一些操作。C#中的併發靜態隊列不保留我的數據

這裏是隊列

public static class MyConcurrentQueue 
{ 
    public static ConcurrentQueue<cRule> _Queue; 

    public static void EnqueueRuleTrigger(cRule _Rule) 
    { 
     MyConcurrentQueue._Queue.Enqueue(_Rule); 
    } 
} 

上的Application_Start我有

MyConcurrentQueue._Queue = new ConcurrentQueue<cRule>(); 

如果我想排隊的規則,我使用

MyConcurrentQueue.EnqueueRuleTrigger(_Rule); //We're done enqueue the rule 

出隊我用

MyConcurrentQueue._Queue.TryDequeue(out _Rule) 

我注意到,如果在一個緊湊的循環排隊2項,1後,其他由第一離隊[單獨的非同步線程]時,在日誌文件中的數據沒有了匹配排隊

如果我在隊列之間進行睡眠,那麼日誌會讀取正確的值,可能是因爲一個項目被放入,被取出,另一個項目被放入,被取出。

我想這是因爲隊列是靜態的,它存儲對_Rule的引用而不是其副本。關於如何解決這個問題的任何想法?我需要隊列可以被多個線程訪問,這就是爲什麼我首先使它成爲靜態的原因。

在此先感謝。

編輯

這是我入隊和日誌和出隊和邏輯日誌

while (x<=y) 
        { 

    MyConcurrentQueue.EnqueueRuleTrigger(_Rule); //We're done enqueue the string AllText = File.ReadAllText(@"C:\Default\New.txt"); 
File.WriteAllText(@"C:\Default\New.txt", AllText + "\r\nEnqueue Alert:" + 
_Rule.AlertID +":" + _Rule.TriggerStartTime + "-" + _Rule.TriggerEndTime); 

} 

這是一個單獨的線程

if (MyConcurrentQueue._Queue.TryDequeue(out _Rule)) 
       { 
... some logic 
    File.WriteAllText(@"C:\Default\New.txt", AllText + "\r\nDequeue Alert:" + 
_Rule.AlertID + ":" + _Rule.TriggerStartTime + "-" + _Rule.TriggerEndTime); 
    } 

這是我的日誌文件

Enqueue Alert:64c88289-58a1-499b-ade9-3 fa69a32cf47:2012/4/27 12:00:00 PM-4/27/2012 5:00:00 PM

Enqueue Alert:64c88289-58a1-499b-ade9-3fa69a32cf47:2012/4/28 2:00 :00 PM-4/28/2012 9:00:00 PM

Dequeue Alert:64c88289-58a1-499b-ade9-3fa69a32cf47:2012/4/28 2:00:00 PM-4/28/2012 9 :00:00 PM

出列提醒:64c88289-58a1-499b-ade9-3fa69a32cf47:2012年4月28日下午二點00分00秒-4 /二千○十二分之二十八下午9時00分○○秒

+0

到目前爲止沒有什麼特別的代碼錯誤,但它不是很清楚什麼是失敗。附註:在發佈示例代碼時,請考慮遵循C#編碼指南,即不要以小寫字母(cRule)開頭的名稱類。 – 2012-04-27 04:19:27

+0

我會檢查編碼準則,謝謝:) 對不起,我有一個日誌文件,當我入隊時,當我出列。 如果我有2項,說A和B a.value中= 1 B.value = 2 我會看起來像 排隊值1 出列值2 排隊值2 出列值的日誌文件2 考慮我在一個線程的循環中排隊A和B,並以另一個線程異步排隊它們。看起來問題是第二次入隊在緊密循環中會覆蓋第一個入隊隊列的值。如果我在排隊之間進行睡眠,日誌會讀取適當的值。 – Jordan 2012-04-27 04:26:45

+0

這使我最終相信我有某種參考問題。因此,一旦隊列中的值正確,我就入隊一次並出隊[因爲我把睡眠放在那裏以確保在日誌寫入之前沒有發生第二次入隊]。 沒有睡眠本質上,第一個對象的第一個出列具有第二個對象的值[與第二個對象一樣] – Jordan 2012-04-27 04:31:01

回答

1

EDIT :看起來是一個射入物體的問題,而不是改變同一物體並第二次射入物體。因爲在出隊期間它看起來像第二個對象覆蓋第一個並被插入兩次,實際上對同一個對象的引用被插入兩次。

最可能的解決方案是在插入之前進行深度克隆。考慮讓你的對象不可變,以簡化代碼的同步和可讀性。

原文:

大多數likly原因是你的日誌代碼不正確同步。由於看起來你想要2動作自動發生(Enqueue + Log或Dequeue + Log),所以你必須在兩個操作中添加適當的鎖定,否則對Queue和Log的調用順序可能是半隨機的。還要確保你正確處理TryDequeue的結果(因爲它可以返回false)。

static object logAndQueueLock = new object(); 
public static void EnqueueRuleTrigger(Rule rule) 
{ 
    lock(logAndQueueLock) 
    { 
     MyConcurrentQueue._Queue.Enqueue(rule); 
     Log.Message("Enqueued:"+ rule.ToString()); 
    } 
} 

public static Rule DequeueRuleTrigger() 
{ 
    lock(logAndQueueLock) 
    { 
     Rule rule = null; 
     if (MyConcurrentQueue._Queue.Enqueue(out rule)){ 
     Log.Message("Enqueued:"+ rule.ToString()); 
     } 
     return rule; 
    } 
} 
+0

請參閱我的更新代碼。我懷疑事實並非如此[雖然我當然可能是錯誤的],因爲我在排隊之後和排隊之後立即執行了日誌記錄操作,您將看到我出來的數據不正確。但是,如果我在兩個隊列之間添加睡眠,我會在日誌中獲得正確的數據。我的懷疑是,當第一次出隊發生時,第二次入隊已經發生了[這是一個緊密的循環],並且規則被當作參考或某物而不是被複制的值,所以他們都共享一個參考。謝謝 – Jordan 2012-04-27 04:49:30

+0

我假設你**不是**在調用TryDeque時使用某種共享成員變量(請參閱我的出隊調用)。否則,你也需要適當的鎖定。請注意,您的跟蹤可能導致條目的任意順序... – 2012-04-27 05:00:00

+0

我應該發佈該部分對不起 'Rule _Rule = new Rule(); if(MyConcurrentQueue._Queue.TryDequeue(out _Rule))' 每次該線程被調用時,它應該創建一個全新的規則。 – Jordan 2012-04-27 05:07:56