即使我锁定了我的列表,我的列表也不是线程安全的

本文关键字:我的 列表 线程 安全 锁定 | 更新日期: 2023-09-27 18:36:30

我得到:

"集合已修改枚举操作可能无法执行"在此 lline 中:

foreach (Message msg in queue)

过了一会儿。

我必须使用 .NET 2.0。

我在私有列表上所做的两个操作<>名为"队列"如下:

// 1st function calls this
lock (queue)
{
      queue.Add(msg);
}
// 2nd function calls this
lock (queue)
{
      using (StreamWriter outfile = new StreamWriter("path", true)
      {
             foreach (Message msg in queue) // This is were I get the exception after a while)
             {
                  outfile.WriteLine(JsonConvert.SerializeObject(msg)); 
             }
              queue = new List<Message>();
      }
}

我做错了什么?

即使我锁定了我的列表,我的列表也不是线程安全的

(下面;好吧,我想不出会导致这种情况的竞争条件......但是:谁知道呢...

首先,你真的需要寻找一些与列表对话的其他代码;问题不在于你发布的代码。我怎么知道?因为在你枚举(foreach (Message msg in queue))的时候,你有一个锁queue,我们没有对锁对象的(非常狡猾,但不相关的)重新分配做任何事情。

对于此foreach错误意味着其他内容正在更改列表。首先要做的,非常简单,是重命名列表字段。这将很快显示其他代码是否触及列表。还要检查您是否永远不会在此代码之外公开列表,即永远不会从任何地方return queue;

问题似乎不在您显示的代码中。重新分配锁定对象是一种不好的做法,你不应该这样做 - 但是:我看不到它实际上会破坏它的场景(显示的代码)。


列表不是这里的最佳模型,重新分配锁定对象不是一个好主意。要是有一个内置类型来表示队列就好了......

private readonly Queue<Message> queue = new Queue<Message>();
...
lock (queue) {
    queue.Enqueue(msg);
}
// 2nd function calls this
lock (queue) {
    if(queue.Count == 0) continue; // taken from comments
    using (StreamWriter outfile = new StreamWriter("path", true) {
        while(queue.Count != 0) {
            Message msg = queue.Dequeue();
            outfile.WriteLine(JsonConvert.SerializeObject(msg)); 
        }
    }
}

无需清除,因为Dequeue本质上和有效地做到这一点。

lick 语句使用的参数应该是只读的。查看此链接

使用readonly private object而不是queqe

代码应该是

eadonly object _object = new object();
// 1st function calls this
lock (_object)
{
      queue.Add(msg);
}
// 2nd function calls this
lock (_object)
{
      using (StreamWriter outfile = new StreamWriter("path", true)
      {
             foreach (Message msg in queue) // This is were I get the exception after a while)
             {
                  outfile.WriteLine(JsonConvert.SerializeObject(msg)); 
             }
              queue = new List<Message>();
      }
}