Подтвердить что ты не робот

Отладка .NET/С#: как отладить классический heisenbug?

Недавно я столкнулся с классическим Heisenbug. Здесь ситуация:

  • У меня есть список деревьев, основной вид на одной панели и подробный вид на другой панели справа, который отображает информацию о выбранном дереве node. (Очень похоже на проводник Windows.)
  • Когда я добавляю новый node в дерево (подумайте о том, чтобы щелкнуть правой кнопкой мыши папку в проводнике Windows и сказать "Создать → Папка" ), выбранный вновь созданный node будет выбран.
  • И вот ошибка: подробный вид справа должен обновиться, чтобы показать новый node. Однако это не так. Мне нужно переключиться на другое дерево node один раз, прежде чем я увижу информацию о новом node в подробном представлении.

Ошибка легко воспроизводится и происходит в конфигурациях сборки "Release" и "Debug". Но: Как только я установил точку останова в обработчике события (для пункта меню "Добавить новый node" ) и включите его, все будет работать отлично = > Heisenbug! Мне не нужно делать настоящую отладку. Нажатие "продолжить" после того, как точка останова попадет, достаточно.

Для лучшего понимания я сделал видео, которое должно иллюстрировать, что происходит.

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

Я бы очень признателен за любые предложения о том, что я могу попытаться определить причину проблемы. Или, может быть, кто-то догадывается о причине?

Я нацелен на структуру 3.5 и использую x86 в качестве платформы решений. Элемент управления списком деревьев находится в DevExpress ' Элементы управления WinForms; Версия Visual Studio - 2010.

Спасибо


Обновление 3: Проблема решена. Проблема заключалась в том, что вызов метода Focus() детального представления не вызвал события GotFocus, что имеет решающее значение для обновления подробного представления. (Я не знаю, почему, возможно, это уже было в центре внимания.) Однако метод не подвел, он просто ничего не сделал.

Теперь я просто фокусирую другой элемент управления, прежде чем сосредоточиться на подробном представлении и на нем. Причина, по которой все хорошо работало во время отладки, заключалось в том, что переход с Visual Studio обратно в мое приложение правильно задал фокус на подробном представлении.

Основным препятствием для поиска этой проблемы было то, что установка контрольной точки в обработчике событий GotFocus бесполезна: в любое время, когда вы пытаетесь переключиться с Visual Studio на приложение, событие GotFocus получает повторное срабатывание, и вы застряли в бесконечной петле. Комментарии о том, как это можно обойти, приветствуются.

Во всяком случае, моя конкретная проблема решена.

Спасибо всем, кто ответил или прокомментировал. Это очень помогло мне.


Обновление 2: В моем коде я выбираю вновь созданный node в дереве. Это вызывает FocusedNodeChangedEvent. В соответствующем обработчике событий я обновляю подробное представление и вызываю его метод Focus().

Кажется, что это не удается, когда нет точки останова. Я думаю, что правильное обновление во время отладки - это то, что детальное представление автоматически получает фокус.


Сообщения окна

Обновление 1: Ниже приведены оконные сообщения, предоставленные с помощью Eddy. (Длинный список удаленных сообщений)

4b9b3361

Ответ 1

Впервые я видел видео для поддержки SO:)

Я думаю, что правая панель или контрольная группа нуждаются (-ыми), чтобы иметь Invalidate(), называемый - который, как мне кажется, срабатывает, потому что он переключается на VS, перегружая окно. Затем, когда вы переключаетесь обратно, он заставляет все перерисовывать, тем самым делая его работу.

Ответ 2

Поместите System.Diagnostics.Debugger.Break() в процедуру обновления для другого окна. Затем, когда появляется ошибка, будет запущена точка прерывания времени выполнения, и вы можете просмотреть стек.

Ответ 3

Когда у вас есть "heisenbug", вам нужно посмотреть, что происходит, но с более легким прикосновением, которое не прерывает поток программы.

Я бы предположил, что вы формируете гипотезу о том, где лежит ваша проблема. Затем я редактировал код для включения вызовов различных методов класса Debug, которые проверяют гипотезу или просто дают информацию о времени выполнения для диагностики, Затем запустите свой код в режиме отладки и посмотрите, что вы получаете на выходе.

Если у вас есть более неуловимый "hiesenbug", тэг происходит только в режиме выпуска, вам нужно будет свернуть свой собственный механизм ведения журнала, чтобы собрать ваши доказательства.

Ответ 4

Кажется, что проблема связана не с тем, чтобы получить правильное событие, вызываемое для запуска и обновления дочерней панели. При попадании на точку останова ваше приложение теряет фокус, и когда вы возвращаете его, он снова получает его (что отличает его от запуска). Чтобы проверить, какие события и не вызваны, а какая разница между двумя сценариями, добавьте следующий код в форму, чтобы увидеть все появившиеся сообщения окна.

protected override void WndProc(ref Message winmsg)
{
  base.WndProc(ref winmsg);
  System.Diagnostics.Debug.WriteLine(winmsg.Msg + " - " + winmsg);
}

Сравнение различий может помочь вам определить способ решения этой проблемы.