2011-05-19 110 views
3

下面的代碼因錯誤「進程無法訪問該文件,因爲它正在被另一進程使用」而失敗。我難以理解什麼是錯的。我以管理員身份運行Visual Studio,而非文件在記事本中打開。c#線程訪問問題

private void Load_Click(object sender, RoutedEventArgs e) 
    { 
     if (txtInput.Text.Length > 1) { 
      //var rootDir = System.IO.Directory.GetCurrentDirectory(); 
      string rootDir = @"C:\b"; 
      string search = txtInput.Text.Replace(" ", ""); 
      List<Thread> searches = new List<Thread>(); 

      foreach (var file in new DirectoryInfo(rootDir).GetFiles().Where(z => z.LastWriteTime > DateTime.Now.AddDays(-7))) { 
       if (file.ToString().Contains(".log")) { 
        searches.Add(new Thread(new ThreadStart(() => AddDropdownItem(file.ToString(),search)))); 
       } 
      } 
      //Run ten threads at a time and wait for them to finish 
      for (int i = 0; i < searches.Count; i = i + 10) { 
       List<Thread> pool = new List<Thread>(); 
       for (int j = 0; j < 10; j++) { 
        if (i + j < searches.Count) { 
         Thread t = searches[(i + j)]; 
         pool.Add(t); 
        } 
       } 

       foreach (Thread t in pool) { 
        t.Start(); 
       } 

       foreach (Thread t in pool) { 
        t.Join(); 
       } 
      } 
     } 
    } 

    private void AddDropdownItem(string file, string search) 
    { 
     if (GetFileContent(file.ToString()).Contains(search)) { 
      ComboBoxItem item = new ComboBoxItem(); 
      item.Content = file.ToString(); 
      Dispatcher.BeginInvoke(new ThreadStart(() => ddFiles.Items.Add(item))); 
     } 
    } 

    private string GetFileContent(string file) 
    { 
     string path = System.IO.Path.Combine(@"C:\b", file); 
     using (FileStream fs = new FileStream(path, FileMode.Open)) { 
      return new StreamReader(fs).ReadToEnd(); 
     } 
    } 
+0

+1作爲對未評論的downvote的支持 – sra 2011-05-19 13:06:02

+0

爲什麼要在你的字符串上調用.ToString()? – thumbmunkeys 2011-05-19 13:08:09

回答

3

這個問題很可能與您在lambda表達式中捕獲循環變量的方式有關。請記住,關閉捕獲變量,而不是。所以基本上AddDropdownItem方法可能會比您認爲的參數file接收不同的值。這是一個衆所周知的與closing over the loop variable行爲警告。

更改循環,以便將循環變量複製到單獨的引用中。

foreach (var file in new DirectoryInfo(rootDir).GetFiles().Where(z => z.LastWriteTime > DateTime.Now.AddDays(-7))) 
{ 
    if (file.ToString().Contains(".log")) 
    { 
    var capture = file; 
    searches.Add(new Thread(new ThreadStart(() => AddDropdownItem(capture.ToString(),search)))); 
    } 
} 

我注意到一個潛在的無關問題。看起來你正在從你的一個工作線程創建一個ComboBoxItem。我確實看到你正在對UI線程進行編組添加操作。我會確保ComboBoxItem也是在UI線程上創建的,以獲得更好的效果。他們的方式,你可能不會造成任何問題,但我會保證安全。我傾向於將UI線程以外的線程無UI元素訪問的規則中斷至其極限。

+0

完美!你的第一個答案解決了我的問題,然後第二個答案解決了我在開始工作時發現的其他錯誤。非常驚訝 – 2011-05-19 13:41:45

1

我看不到'AddDropDownItem',但我打賭你打開文件在那裏,而不是關閉文件時,線程完成他們。取消分配變量(或者讓它們超出範圍並讓GC處理它)是不夠的。在線程完成之前首先明確關閉這些文件。

+0

所有代碼都在上面的示例中。我把文件流放在一個使用塊中。我也只是試圖明確關閉它,但它並沒有幫助 – 2011-05-19 13:20:55

+0

你打開其他文件的其他地方? – Andrew 2011-05-19 13:28:52