0

我已經使用了BackgroundWorkers很多,但我從未遇到過這個問題。我的程序分析了邏輯分析儀產生的數據包的輸出,其中有數千個。爲了防止在我的表單中更新ListView(我之前報告發現的每一個,並且表單完全沒有響應),我在一個通用列表(列表<Packet>)中收集BackgroundWorker中的數據包並且然後報告發現有n個數量(當前爲250),或發生異常或完成時。C#:如何解決BackgroundWorker進度報告回調中的「集合被修改」?

當我遍歷列表時,發生在我的回調中的問題<數據包>我收到InvalidOperationException,其中「Collection was modified」錯誤。我沒有觸及foreach中的集合(我正在添加到另一個集合中,但我沒有看到任何理由可能會修改我正在迭代的集合 - 並且將其註釋掉並不能解決問題。)甚至試圖鎖定e.UserState,將e.UserState存儲到本地範圍列表<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"); 
} 
+0

你在評論什麼? >>我沒有觸及foreach中的集合(我正在添加到另一個集合中,但我沒有看到任何理由可以修改我正在迭代的集合 - 加上評論它並不能解決問題。)< < – Les 2010-10-02 12:23:22

+0

(列表<數據包)e.UserState是每次調用的同一個列表,還是每次都是新的? – Les 2010-10-02 12:51:28

回答

5

你的問題的一個簡單的解釋是您在ProgressChanged事件處理程序中使用鎖定,但不在DoWork事件處理程序中使用鎖定。這讓工作線程仍然在修改集合,而UI線程正在迭代它。

這很容易解決,只需在工作者中調用ReportProgress之後立即創建一個新的>清單<>。 UI線程現在是唯一一個引用列表的人,你不需要再使用鎖。

+0

我試過了: List <Packet> new_packets =(List <Packet>)e.UserState; 作爲worker_ProgressChanged()方法的第一行,但它沒有解決問題。 – PeterBelm 2010-10-02 12:18:09

+0

我重讀了你的評論,並意識到我誤解了你在說什麼。我嘗試在調用ReportProgress之後添加DoWork內部的行,並修復它。非常感謝! – PeterBelm 2010-10-02 12:25:10

+0

請您分享解決方案代碼嗎? – Cheburek 2013-03-11 12:22:56

0

您不能修改在其上有一個foreach迭代的集合。您正在調用foreach循環內的packets.Add方法,並且我懷疑這個變量指向您正在迭代的同一個集合。

如果這不是您可以嘗試鎖定在您在窗體中聲明一個私有的靜態字段的情況:

private static object _syncRoot = new object(); 

然後:

lock (_syncRoot) 
{ 
    ... 
} 
+0

感謝您的回覆,但是'數據包'已經是表單中的一個私有靜態屬性,在表單構造函數中初始化,並且唯一的其他引用是packets.Add行。所以它絕對不是指同一個集合。同時鎖定它並不能解決問題。 – PeterBelm 2010-10-02 12:13:50

0

我發現如果性能不是一個大問題,那麼使用一些併發安全的集合工作得很好。更多信息here

0

在這個方法中創建packet,然後它不可能別名迭代的方法。

相關問題