2012-04-27 60 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