2014-09-28 66 views
0

下面的代碼迭代List集合。 Server對象只包含描述和URL屬性,並在程序執行開始時填充。從多個後臺更新ListView任務不斷添加相同的ListViewItem

對於List<Server>中的每個服務器,我開始一個新任務,調用一個名爲GetMonitorData的函數。 GetMonitorData只是讀取遠程文件,解析出一些數據,並返回包含解析出的數據的ListViewItem。最後,在任務完成之後我添加了返回ListViewItemListViewContinueWith()

foreach (Server server in Servers) 
{ 
    Task<ListViewItem> mainTask = Task.Factory.StartNew<ListViewItem>(() => 
    { 
     return GetMonitorData(server); 
    }); 

    Task contTask = mainTask.ContinueWith(task => 
    { 
     lstServers.Items.Add(task.Result); 
    }, TaskScheduler.FromCurrentSynchronizationContext()); 

    //System.Threading.Thread.Sleep(500); 
} 

private ListViewItem GetMonitorData(Server server) 
{ 
    XDocument monitorDoc = XDocument.Load(server.MonitorURL); 
    string version = monitorDoc.Root.Element("version").Value; 
    ListViewItem lstItem = new ListViewItem(new string[] { server.ClientName, version }); 
    return lstItem; 
} 

public class Server 
{ 
    public string ClientName { get; set; } 
    public string MonitorURL { get; set; } 
} 

出於某種原因,雖然我只是繼續得到同樣ListViewItemContinueWith(),所以我的ListView在同一ListViewItem的多個副本它。有趣的是,如果我取消對System.Threading.Thread.Sleep(500)行的註釋(從而使任務有一點時間完成),我將按照預期爲List<Server>中的每個服務器獲取唯一的ListViewItem

我錯過了什麼?

+0

也許'GetMonitorData()'不是線程安全的。你可以發佈'GetMonitorData'的代碼嗎? – 2014-09-28 08:39:02

+0

您的'GetMonitorData'方法是線程安全的嗎? – 2014-09-28 08:40:29

+0

嘗試[lock](http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx)'GetMonitorData()'。 無論如何,沒有人能夠幫助你,如果不顯示更多的代碼 – nicks 2014-09-28 08:55:03

回答

0

我發現了一個可行的解決方案!在創建任務之前,我先將傳遞給GetMonitorData()的參數分配給一個臨時變量。請參見下面修改後的代碼:

foreach (Server server in Servers) 
{ 
    Server tmpServer = server; 
    Task<ListViewItem> mainTask = Task.Factory.StartNew<ListViewItem>(() => 
    { 
     return GetMonitorData(tmpServer); 
    }); 

    Task contTask = mainTask.ContinueWith(task => 
    { 
     lstServers.Items.Add(task.Result); 
    }, TaskScheduler.FromCurrentSynchronizationContext()); 
} 

我沒有,雖然這出我自己,this link提供了重要線索。