проблема доступа к потокам c #

#c# #multithreading

#c# #многопоточность

Вопрос:

Приведенный ниже код завершается ошибкой «Процесс не может получить доступ к файлу, поскольку он используется другим процессом». Я в замешательстве относительно того, что не так. Я запускаю Visual Studio от имени администратора, и ни один из файлов не открыт в блокноте.

     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();
        }
    }
  

Комментарии:

1. 1 в качестве поддержки против не прокомментированного снижения

2. почему ты звонишь. toString() в ваших строках?

Ответ №1:

Проблема, скорее всего, связана с тем, как вы фиксируете переменную цикла в лямбда-выражении. Помните, что замыкания фиксируют переменную, а не значение. Таким образом, в принципе, AddDropdownItem метод может получать другое значение для параметра file , чем вы думаете. Это хорошо известное поведенческое предостережение при закрытии переменной цикла.

Измените цикл таким образом, чтобы скопировать переменную цикла в отдельную ссылку.

 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 из одного из своих рабочих потоков. Я вижу, что вы маршалируете операцию добавления в поток пользовательского интерфейса. Я бы убедился, что ComboBoxItem также создается в потоке пользовательского интерфейса для хорошей оценки. То, что у вас есть, вероятно, не вызовет никаких проблем, но я бы перестраховался. Я склонен доводить правило о запрете доступа к элементам пользовательского интерфейса из потока, отличного от потока пользовательского интерфейса, до крайнего предела.

Комментарии:

1. Это идеально! Ваш первый ответ решил мою проблему, затем второй решил другую ошибку, которую я обнаружил, когда она начала работать. Высоко ценится

Ответ №2:

Я не вижу ‘AddDropDownItem’, но я готов поспорить, что вы открываете файл там и не закрываете файлы, когда поток с ними закончен. Освободить переменные (или просто позволить им выпадать из области видимости и позволить GC обрабатывать это) недостаточно. Сначала явно закройте файлы, прежде чем поток завершится.

Комментарии:

1. Весь код приведен в примере выше. Я поместил поток файлов в блок using. Я также только что попытался явно закрыть его, но это не помогло

2. Вы открываете какие-либо другие файлы где-то еще?