Ошибка при поиске файлов

Имею код

        private void MakeDriveList(char driveLetter)
        {
            List<ListItem> roots = treeListView1.Roots.Cast<ListItem>().ToList();
            DriveInfo driveInfo = new DriveInfo(driveLetter.ToString());

            ListItem rootListItem = new ListItem(driveInfo.Name, ListItemType.Disk, null);
            rootListItem.Size = driveInfo.TotalSize;
            rootListItem.DiskInfo.FreeSpace = driveInfo.AvailableFreeSpace;
            string displayName = $"{driveInfo.Name} {driveInfo.AvailableFreeSpace} / {driveInfo.TotalSize}";
            rootListItem.DisplayName = displayName;

            ParseDir(driveInfo.Name, rootListItem);

            roots.Add(rootListItem);
            treeListView1.UpdateObjects(roots);

            dateCreated = DateTime.Now;
            lblDateModified.Text = $"Изменён: {dateCreated}";

            void ParseDir(string dir, ListItem rootItem)
            {
                string[] rootDirs = Directory.GetFileSystemEntries(dir).Where(f => Directory.Exists(f)).ToArray();
                string[] rootFiles = Directory.GetFileSystemEntries(dir).Where(f => File.Exists(f)).ToArray();

                foreach (string subDir in rootDirs)
                {
                    string subDirName = Path.GetFileName(subDir);
                    ListItem item = new ListItem(subDirName, ListItemType.Directory, rootItem);
                    try
                    {
                        DirectoryInfo directoryInfo = new DirectoryInfo(subDir);
                        item.DateCreated = directoryInfo.CreationTime;
                        item.DateModified = directoryInfo.LastWriteTime;
                        item.AttributesString = AttributesToString(directoryInfo.Attributes);
                        ParseDir(subDir, item);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                    }
                    rootItem.Children.Add(item);
                }

                foreach (string file in rootFiles)
                {
                    string fileName = Path.GetFileName(file);
                    ListItem item = new ListItem(fileName, ListItemType.File, rootItem);
                    try
                    {
                        FileInfo fileInfo = new FileInfo(file);
                        item.Size = fileInfo.Length;
                        item.DateCreated = fileInfo.CreationTime;
                        item.DateModified = fileInfo.LastWriteTime;
                        item.AttributesString = AttributesToString(fileInfo.Attributes);
                        displayName = $"{fileName} [{item.Size}] [{item.AttributesString}]";
                        item.DisplayName = displayName;
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                    }
                    rootItem.Children.Add(item);
                }
            }
        }

Всё это выводится в TreeListView.
Если указать диск, содержащий дофига файлов, то появляется вкладка студии Приложение находится в режиме приостановки выполнения и экскепшен Помощник по отладке управляемого кода "ContextSwitchDeadlock" : "CLR не удалось перейти из COM-контекста 0x7c91e0 в COM-контекст 0x7c9128 за 60 секунд. Наиболее вероятно, что поток, владеющий контекстом/апартаментом назначения, находится в режиме ожидания или выполнения очень длительной операции без прокачки сообщений Windows. Обычно эта ситуация отрицательно влияет на производительность и даже может привести к зависанию приложения или чрезмерному расходованию памяти. Чтобы избежать этой проблемы, все потоки однопоточного апартамента (STA) должны использовать примитивы ожидания для прокачки (например, CoWaitForMultipleHandles) и периодически прокачивать сообщения во время длительных операций."
Чё это значит? :dizzy_face: Всё же в одном потоке выполняется. Какое ему дело до того, как долго выполняется код?

Это вроде сама студия выдает, а на самом деле программа из-за этого не упадет.
Можно отключить в Debug → Exceptions → Managed Debug Assistants → ContextSwitchDeadlock
c# - Visual Studio: ContextSwitchDeadlock - Stack Overflow

Ну а происходит это видимо потому что оно как раз в основном потоке, вешает UI.
Винда через какое-то время выдает диалог о зависании.

в русской версии не вижу ничего похожего :man_shrugging:

Поэтому надо брать английскую, как минимум проще гуглить и т.д. :kolobokbatya:

Ну где-то в меню сверху про отладку должно быть что-то про исключения.

Потому что не правильно делать блокирующие процедуры в основном UI. Приложение перестает обрабатывать стандартные сообщения операционной системы и считает что приложение висит.
Нормальное поведение в мультизадачных ОС.

Я просто с перевода угараю. Помните же, как Diablo 2 было переведено? :kolobok:

Ну в этом и проблема. Про отладку вижу, про исключения не вижу.

Ну для ОС нормальное. А студии-то какое дело? Она же видит, что цикл выполняется. Значит, поток не висит. Висит только GUI. А это уже не её дело.

Screenshot_trim
нету тут никаких исключений

Похоже, теперь оно тут
image

Но вообще лучше ж не отключать, а сделать, чтоб основной поток не висел.

Если бы система была настолько умна что анализировала бы ваш код то вы там и не очень то нужны были бы. Система видит что отлаживаемое приложение не отвечает на сообщения. Каким образом можно продолжать процесс отладки если пациент не подает никакой обратной связи?? Ну неужели это не ясно.

while(true); тоже вроде бы код. Тоже цикл. И со стороны системы это не ошибочный код, но из за отсутствия связи с отладчиком вы также получите приостановку процесса потому как подобное поведение программ это плохо. Почти также плохо как goto.

Зачем ему сообщения? В других потоках их вообще нет.

Отладке это не мешает

Гоуту плох только тем, что может сделать код сложным для понимания. Об этом (и о циклах без условий конца) линтеры предупреждать должны, а не отладчик.

Кстати, это легко делается таким костылём:


                int iter = 0;
                foreach (string file in rootFiles)
                {
                    if (iter++ % 15 == 0)
                    {
                        lblDateModified.Text = $"Сканирование: {file}";
                        Application.DoEvents();
                    }
                    ......

Но тогда возникает проблема: отображается не каждый файл. А если отображать каждый, то возникнет другая проблема: будет слишком часто вызываться DoEvents(). На производительность это, вроде, не сильно влияет. Но ведь плохо, когда DoEvents() часто вызывается.
А если делать поиск в отдельном потоке, то нужна будет синхронизация. А это ещё более долгая операция.

Ну так я же об этом и говорю. Если программа запущена без дебаггера - поведение одно. А если в дебаггере - другое. На то он и дебаггер + среда разработки.

Ну так придумали бы что-нибудь. Это же дебаг, а не рантайм. Наверняка, можно как-то отследить. В Delphi, вроде, дебаггеру пофиг, умер GUI или нет. Почему дебаггеру C Sharpа не пофиг на окно WInForms - не понятно :man_shrugging: Он же не окно дебажит, а процесс. Он, по-идее, об окне и его сообщениях и знать-то не должен :thinking:

Вот чтобы такого гемороя не было и придумали async. И основной гуи не повиснет.

И что? А синхронизация разве не нужна? :thinking:


        private void Test()
        {
            for (int i = 0; i < 1000; i++)
            {
                label1.Text = i.ToString();
            }
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            await Task.Run(Test);
        }

Без синхронизации не работает. В чём тогда смысл? :man_shrugging:

В потоке можно делать всё то, что не гуй.
А гуй обновлять с помощью IProgress и т.д.

Разве так быстрее будет, чем с DoEvents()?

хз что быстрее, но так удобнее и правильнее )

Быстрее или нет, это в целом не важно. Я имею ввиду, что мне кажется, что если на каждый найденный файл вызывать DoEvents() или IProgress, то процесс захлебнётся сообщениями :thinking:

Так можно не на каждый )

Если не на каждый, то может возникнуть третья проблема. У меня есть полудохлый HDD (естественно, с самыми важными файлами во вселенной), который еле читается. Он, при включении, инициализируется минут 10 и файлы читает очень медленно. Даже список файлов вычитывается очень тяжко. Радует только то, что он в принципе ещё не умер.
Если отображать не каждый файл, то будет ощущение, что всё зависло.

Для такого можно в функции/классе отправки прогресса перед самой отправкой проверять сколько времени прошло с последней отправки, если больше секунды, то отправлять.