Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# System.InvalidOperationException:已修改集合_C#_Collections_Thread Safety - Fatal编程技术网

C# System.InvalidOperationException:已修改集合

C# System.InvalidOperationException:已修改集合,c#,collections,thread-safety,C#,Collections,Thread Safety,在通过队列枚举时,我遇到以下异常: System.InvalidOperationException: 收集被修改;列举 操作可能无法执行 以下是代码摘录: 1: private bool extractWriteActions(out List<WriteChannel> channelWrites) 2: { 3: channelWrites = new List<WriteChannel>(); 4: foreach (Tpo

在通过队列枚举时,我遇到以下异常:

System.InvalidOperationException: 收集被修改;列举 操作可能无法执行

以下是代码摘录:

1:    private bool extractWriteActions(out List<WriteChannel> channelWrites)
2:    {
3:        channelWrites = new List<WriteChannel>();
4:        foreach (TpotAction action in tpotActionQueue)
5:        {
6:            if (action is WriteChannel)
7:            {
8:                channelWrites.Add((WriteChannel)action);
9:                lock(tpotActionQueue)
10:               {
11:                  action.Status = RecordStatus.Batched;
12:               }
13:           }
14:       }
15:       return (channelWrites.Count > 0);
16:   }
1:private bool extractWriteActions(out List channelWrites)
2:    {
3:channelWrites=新列表();
4:foreach(tpotActionQueue中的TpotAction操作)
5:        {
6:if(操作为写通道)
7:            {
8:channelWrites.Add((WriteChannel)操作);
9:锁(tpotActionQueue)
10:               {
11:action.Status=RecordStatus.Batched;
12:               }
13:           }
14:       }
15:返回(channelWrites.Count>0);
16:   }
我想我理解这个问题——在
action.Status=RecordStatus.Batched
处更改哈希表,这会使枚举器上的MoveNext()出错。
问题是,我如何正确地实现这个“模式”?

我认为您需要做的就是停止使用foreach,而是将其切换到for循环

for(int i = 0; i < tpotActionQueue.Length; i++)
{
     TpotAction action = tpotActionQueue[i];

     if (action is WriteChannel)
     {
        channelWrites.Add((WriteChannel)action);
        lock(tpotActionQueue)
        {
           action.Status = RecordStatus.Batched;
        }
     }
}
for(int i=0;i

您好,Mike。

我想您在迭代TpotationQueue时,一定有其他线程在修改它。由于您仅在for循环中锁定该队列,因此这是可能的。

允许您更改集合中某个项的值。您收到的错误意味着项目已被添加或删除,即:集合本身已被修改,而不是集合中的项目。这很可能是由另一个线程向该集合添加或删除项引起的

您应该在方法的开头锁定队列,以防止其他线程在您访问集合时修改集合。或者,您可以在调用此方法之前锁定集合

private bool extractWriteActions(out List<WriteChannel> channelWrites)
    {
      lock(tpotActionQueue)
      {
        channelWrites = new List<WriteChannel>();
        foreach (TpotAction action in tpotActionQueue)
        {
            if (action is WriteChannel)
            {
                channelWrites.Add((WriteChannel)action);

                  action.Status = RecordStatus.Batched;

           }
        }
      }
       return (channelWrites.Count > 0);
   }
private bool extractWriteActions(out List channelWrites)
{
锁(tpotActionQueue)
{
channelWrites=新列表();
foreach(tpotActionQueue中的TpotAction操作)
{
if(操作为WriteChannel)
{
channelWrites.Add((WriteChannel)操作);
action.Status=RecordStatus.Batched;
}
}
}
返回(channelWrites.Count>0);
}

我想我在一个集合上使用
foreach
循环时也遇到了类似的异常,我试图从集合中删除项目(或者它可能是一个列表,我不记得了)。我最终通过使用
for
循环绕过了它。或许可以尝试以下方法:

for (int i=0; i<tpotActionQueue.Count(); i++)
{
    TpotAction action = tpotActionQueue.Dequeue();
    if (action is WriteChannel)
    {
        channelWrites.Add((WriteChannel)action);
        lock(tpotActionQueue)
        {
            action.Status = RecordStatus.Batched;
        }
    }
}

for(int i=0;i您没有
tpotActionQueue
的定义,但是如果它只是一个普通的
列表
,那么该行不是您的问题。修改集合是添加或删除成员,而不是在包含的对象上设置属性


您有一个
锁(tpotActionQueue)
和一个线程安全标签,所以我猜在您枚举时,会有另一个线程从
tpotActionQueue
中添加或删除项目。您可能需要同步这些访问。

有什么好消息吗

private bool extractWriteActions(out List<WriteChannel> channelWrites)
{

   channelWrites= tpotActionQueue.Where<WriteChannel>(x => x is WriteChannel).ToList()

   foreach(WriteChannel channel in channelWrites) {
      channel.Status = RecordStatus.Batched;
   }

  return ( channelWrites.Count > 0);
}
private bool extractWriteActions(out List channelWrites)
{
channelWrites=tpotActionQueue.Where(x=>x是WriteChannel.ToList())
foreach(channelWrites中的WriteChannel通道){
channel.Status=RecordStatus.Batched;
}
返回(channelWrites.Count>0);
}

为什么要锁定队列?这个代码对我来说毫无意义。@Kermit\u xc:枚举器文档中更重要的一点是"枚举器没有对集合的独占访问权限;因此,通过集合进行枚举本质上不是线程安全的过程。为保证枚举期间的线程安全,可以在整个枚举期间锁定集合。若要允许多个线程访问集合进行读写,请必须执行你自己的同步。“对。这个代码不做任何模糊的事情。如果你需要在多线程上同步读写器,考虑使用读写器锁。这仍然会在多线程环境中造成问题,看起来TPATActuon队列是一个“全局的”。"变量,另一个线程可能会在调用此方法时对其进行修改。此外,允许您更改集合中的项,因此我看不出这有什么意义。dang!-刚刚验证,在集合上有不同的线程推动元素,但是pops是线程安全的。我有点担心整个迭代的“锁定”性能吗尽管如此。它对时间非常敏感-可能需要完全返工:{。尽管如此!@kermit_xs:“刚刚验证,在集合上有不同的线程推送元素”-这就是你的问题。从“foreach”更改为“for”循环不是您的问题,也不是问题的答案。使用foreach时,您需要在枚举之前锁定集合。枚举数不是线程安全的。是的,但此方法不会删除或向集合中添加项。问题不在此方法范围内。非常感谢,这很有意义…将尝试一下。不,Stan问题在于操作。状态分配,请阅读任何集合的枚举文档。“只要集合保持不变,枚举数就保持有效。如果对集合进行了更改,如添加、修改或删除元素,则枚举数将不可恢复地无效,其行为也未定义”.在这里,他正在修改一个您从未使用过foreach初始化列表的元素?list t=new list();t.Add(new Test());t.Add(new Test());foreach(