C#:如何在BackgroundWorker进度报告回调中解决"Collection was modified"?

Pet*_*elm 0 c# collections multithreading generic-list backgroundworker

我已经使用了BackgroundWorkers了,但我以前从未遇到过这个问题.我的程序分析逻辑分析仪的输出,产生数据包,其中有数千个.为了防止更新延迟更新我的表单中的ListView(我之前报告了每个发现的,并且表单完全没有响应)我正在收集通用列表(List <Packet>)中的BackgroundWorker内的数据包和然后报告当找到n量(当前为250),或者发生异常时,或者当它完成时.

当我在List <Packet>上进行迭代时,问题发生在我的回调中,我得到一个InvalidOperationException,其中包含"Collection was modified"错误.我没有触及foreach中的集合(我正在添加到另一个集合中,但我认为没有理由可以修改我正在迭代的集合 - 再加上评论它不能解决问题.)我是甚至尝试锁定e.UserState,将e.UserState存储到本地作用域List <Packet>并锁定,似乎没有任何作用.

这是我的回调方法的代码:

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar.Value = e.ProgressPercentage;
    packetsListView.SuspendLayout();
    lock ((List<Packet>)e.UserState)
    {
        foreach (Packet packet in (List<Packet>)e.UserState)
        {
            packets.Add(packet);
            ListViewItem item = new ListViewItem(string.Format("{0}ns", Math.Round(packet.StartSampleNumber * 41.666667)));
            item.Tag = packet;
            item.SubItems.Add(new ListViewItem.ListViewSubItem(item, packet.Description));
            packetsListView.Items.Add(item);
        }
    }
    packetsListView.ResumeLayout();

    statusLabel.Text = string.Format("Analyzing...found {0} {1}", packetsListView.Items.Count, packetsListView.Items.Count == 1 ? "packet" : "packets");
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 5

对您的问题的一个简单解释是您在ProgressChanged事件处理程序中使用锁,但在DoWork事件处理程序中不使用.这使得工作线程在UI线程迭代时仍然可以修改集合.

解决它很简单,只需在worker中调用ReportProgress后立即创建一个新的 List <>.UI线程现在是唯一具有列表引用的线程,您不再需要使用锁定.