2011-05-19 113 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