#c# #.net #vb.net #parallel-processing
Вопрос:
Есть какие-либо предложения о том, как писать повторяемые модульные тесты для кода, который может быть подвержен блокировкам и условиям гонки?
Прямо сейчас я склоняюсь к тому, чтобы пропустить модульные тесты и сосредоточиться на стресс-тестах. Проблема в том, что вы можете запустить стресс-тест 5 раз и увидеть пять разных результатов.
РЕДАКТИРОВАТЬ: Я знаю, что это, вероятно, просто сон, но если бы был способ контролировать отдельные потоки и заставлять их выполнять по одной инструкции за раз, я мог бы чего-то добиться.
Комментарии:
1. Отказ от ответственности: Я работаю в Typemock. Я видел комментарии, касающиеся Typemock Racer, и я хочу прояснить несколько вещей: 1. Racer не является «инструментом стресс-тестирования», он использует алгоритмы статического и динамического анализа для обнаружения тупиков в коде .NET. Это означает, что в случае, если с помощью Racer не было обнаружено взаимоблокировки, взаимоблокировки не существует (если только у нас нет ошибки :)). 2. Мы усердно работаем над добавлением обнаружения условий гонки в Racer — В (ближайших) будущих версиях у нас будет анализ условий гонки, но текущая версия обнаруживает только взаимоблокировку. 3. Наконец — Гонщик находится в альфа-стадии, что означает, что его можно бесплатно скачать и использовать.
Ответ №1:
Взгляните на TypeMock Racer (он в бета-версии)
редактировать: на самом деле Альфа
http://www.typemock.com/Typemock_software_development_tools.html
Комментарии:
1. Назовите меня скептиком. У меня были расовые условия, которые я не мог воспроизвести даже после того, как выяснил, что их вызывает. TypeMock Racer может найти что-то, но это всего лишь стресс-тест. Прохождение не означает, что у них нет никаких условий для гонки. И все же это может быть полезно.
2. Это не совсем «модульный тест», но тем не менее он может быть полезен.
3. Нет, могу прочитать ИЛ и сказать вам, если у вас тупик, а затем поставить вас в затруднительное положение. Я только что получил демо, но я понял, что они имели в виду, когда они объяснили это.
4. Я согласен, что это может быть очень полезно, но я не верю, что это модульный тест в том смысле, что прохождение означает, что у вас нет тупиков или условий гонки.
5. Ссылки больше не действительны.
Ответ №2:
Обычно можно принудительно выполнить предусмотренные условия гонки и взаимоблокировки, используя такие вещи, как ManualResetEvent, чтобы перевести каждый поток в ожидаемое состояние перед его освобождением, т. Е. Заставить поток A заблокировать и дождаться сигнала… заставьте поток B запросить блокировку и т. Д…
Однако — обычно вы можете написать такой тест для расследования предполагаемой ошибки, чтобы доказать, когда она исправлена и что она не всплывает повторно. Вы, как правило, разрабатываете условия гонки (но тестируете их настолько хорошо, насколько это прагматично).
Комментарии:
1. Будьте осторожны — ожидание события вызывает сброс кэша, который может маскировать состояние гонки. В этой ситуации может быть полезно использовать циклы for для задержек.
2. Достаточно справедливо — я больше говорил о том, чтобы доказать последствия тупика и показать, что они исправлены, — но точка зрения принята.
Ответ №3:
Я не думаю, что поиск условий гонки действительно входит в сферу модульного тестирования. Более или менее по определению, единственный способ проверить условия гонки-это псевдослучайно. Если вы не готовы приложить усилия для официального подтверждения правильности вашей стратегии блокировки, вам придется провести стресс-тестирование.
Вам все равно нужно писать модульные тесты, чтобы проверить правильность алгоритмов, а не стратегию блокировки.
При стресс-тестировании многопоточного кода вы захотите протестировать в условиях, когда у вас один процессор на поток, где у вас несколько потоков, совместно использующих процессор, и где у вас больше процессоров, чем потоков (если это возможно).
Ответ №4:
Вы можете написать класс блокировки, который обнаруживает потенциальные тупики, посмотрев на порядок операций блокировки. Мы делаем это, имея контекст потока, в котором регистрируются все блокировки при их получении (можно сделать опцию только для ОТЛАДКИ).
Идея состоит в том, чтобы создать график, в котором узлы представляют блокировки, а направленное ребро между A и B означает, что «блокировка A удерживалась, когда была получена блокировка B». Позвольте вашей программе работать с обычными нагрузками, затем проверьте наличие циклов на графике. Цикл означает, что существует вероятность взаимоблокировки, даже если ваш код не попал в нее.
Ответ №5:
Не могу придумать хороший автоматизированный способ, но ближе всего я подошел к написанию модульного теста, который «выявил бы» тупик, используя точки останова в дополнение к модульному тесту. Я просто добавил некоторые инструкции о том, где добавить точку останова. Требуется некоторое ручное усилие, но с их помощью вы всегда можете раскрыть свое расписание потоков в худшем случае.
Возможно, кто-то придумал хороший способ автоматизации такого рода функций? Я мог бы представить себе автоматический запуск отладчика, разрыв одного потока в определенной строке, запуск другого до определенного состояния, а затем утверждение для модульного теста.
Комментарии:
1. Проблема с точками останова заключается в том, что это изменяет поведение кода. Некоторые действия, такие как изменение порядка команд и вставка, не выполняются при подключении отладчика.
Ответ №6:
Ранее я использовал искусственные задержки в коде, которые запускаются некоторыми параметрами в запросе. Например, один запрос указывает серверу задерживать запись между двумя записями, а другой-выполнять их без задержки между ними.
Марк Бесси пишет, что это полезно только для создания репро, а не для обнаружения проблемы.
Ответ №7:
Вы пробовали Corensic Jinx?