0

所以我有在一个线程中处理并放入队列的数据,然后另一个线程将信息出队并对其执行一些操作。

这是队列

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);
    }

这是我的日志文件

排队警报:64c88289-58a1-499b-ade9-3fa69a32cf47:4/27/2012 12:00:00 PM-4/27/2012 5:00:00 PM

排队警报:64c88289-58a1-499b-ade9-3fa69a32cf47:4/28/2012 2:00:00 PM-4/28/2012 9:00:00 PM

出队警报:64c88289-58a1-499b-ade9-3fa69a32cf47:4/28/2012 2:00:00 PM-4/28/2012 9:00:00 PM

出队警报:64c88289-58a1-499b-ade9-3fa69a32cf47:4/28/2012 2:00:00 PM-4/28/2012 9:00:00 PM

4

1 回答 1

1

编辑: 将对象加入队列似乎是一个问题,而不是更改同一个对象并将其第二次加入队列。结果在出队期间,看起来第二个对象覆盖了第一个对象并被插入了两次,实际上对同一对象的引用被插入了两次。

最可能的解决方案是在插入之前进行深度克隆。考虑使您的对象不可变以简化代码的同步和可读性。

原来的:

最可能的原因是您的日志记录代码未正确同步。由于看起来您希望 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; 
    } 
} 
于 2012-04-27T04:36:33.060 回答