Читая комментарии к этому ответу , а именно:
Тот факт, что вы не можете написать тест, не означает, что он не сломан. Неопределенное поведение, которое обычно работает должным образом (C и C ++ полны этого), условия гонки, потенциальное переупорядочение из-за слабой модели памяти ... - CodesInChaos 7 часов назад
@CodesInChaos, если он не может быть воспроизведен, то код, написанный для исправления, также не может быть протестирован. И, по моему мнению, использование непроверенного кода в жизни - худшее преступление - RhysW 5 часов назад
... меня интересует, существуют ли какие-либо хорошие общие способы последовательного запуска очень редко возникающих производственных проблем, вызванных условиями гонки в тестовом примере.
testing
multithreading
Дэн Нили
источник
источник
Ответы:
Будучи в этом сумасшедшем бизнесе примерно с 1978 года, проведя почти все это время во встроенных вычислениях в реальном времени, работая в многозадачных, многопоточных, многозадачных системах, иногда с несколькими физическими процессорами, погнавшись за мою долю гонок. Условия, мое взвешенное мнение, состоит в том, что ответ на ваш вопрос довольно прост.
Нет.
Нет хорошего общего способа вызвать состояние гонки при тестировании.
Ваша ЕДИНСТВЕННАЯ надежда состоит в том, чтобы создать их полностью из вашей системы.
Когда и если вы обнаружите, что кто-то вставил его, вы должны заколоть его муравейником, а затем перепроектировать, чтобы устранить его. После того, как вы разработали его фальшивку (произносится как f *** up) из вашей системы, вы можете освободить его от муравьев. (Если муравьи уже поглотили его, оставив только кости, поставьте табличку с надписью «Это то, что происходит с людьми, которые ставят гоночные условия в проект XYZ!» И оставьте его там.)
источник
Если вы находитесь в цепочке инструментов MS. Ms Research создала инструмент, который будет вызывать новые чередования для каждого пробега и может воссоздавать неудачные пробежки, которые называются шахматами .
вот видео, показывающее это в использовании.
источник
Лучший инструмент, который я знаю для такого рода проблем, - это расширение Valgrind под названием Helgrind .
По сути, Valgrind моделирует виртуальный процессор и запускает ваш двоичный файл (без изменений) поверх него, поэтому он может проверять каждый доступ к памяти. Используя эту структуру, системные вызовы Helgrind watch делают вывод, что доступ к общей переменной не защищен должным образом механизмом взаимного исключения. Таким образом, он может обнаружить теоретическое состояние расы, даже если это на самом деле не произошло.
Intel продает очень похожий инструмент под названием Intel Inspector .
Эти инструменты дают отличные результаты, но ваша программа будет значительно медленнее во время анализа.
источник
Чтобы выявить многопоточную ошибку, необходимо заставить разные потоки выполнения выполнять свои шаги в определенном порядке чередования. Обычно это трудно сделать без ручной отладки или манипулирования кодом, чтобы получить какую-то «ручку» для управления этим перемежением. Но изменение кода, который ведет себя непредсказуемо, часто будет влиять на эту непредсказуемость, поэтому это трудно автоматизировать.
Хороший трюк описан Ярославом Тулачем в « Практическом API-дизайне» : если у вас есть операторы логирования в рассматриваемом коде, манипулируйте потребителем этих операторов логирования (например, внедренным псевдотерминалом), чтобы он принимал отдельные сообщения журнала в определенном заказ на основе их содержания. Это позволяет вам контролировать чередование шагов в разных потоках без необходимости добавлять что-либо в производственный код, которого там еще нет.
источник
Невозможно быть абсолютно уверенным, что различные типы неопределенного поведения (в частности, в условиях гонки) не существуют.
Тем не менее, есть ряд инструментов, которые показывают множество таких ситуаций. Вы можете доказать, что в настоящее время существует проблема с такими инструментами, даже если вы не можете доказать, что ваше исправление действительно.
Несколько интересных инструментов для этой цели:
Valgrind это проверка памяти. Он обнаруживает утечки памяти, считывает неинициализированную память, использует висячие указатели и доступ за пределы.
Helgrind - это средство проверки безопасности потоков. Он находит условия гонки.
Оба работают с помощью динамического инструментария, то есть они принимают вашу программу как есть и выполняют ее в виртуализированной среде. Это делает их ненавязчивыми, но медленными.
UBSan - это неопределенная проверка поведения. Он находит различные случаи неопределенного поведения C и C ++, такие как целочисленные переполнения, сдвиги вне диапазона и тому подобное.
MSan это проверка памяти. У него такие же цели, как у Valgrind.
TSan - это проверка безопасности потока. У него те же цели, что и у Хелгринда.
Эти три встроены в компилятор Clang и генерируют код во время компиляции. Это означает, что вам нужно интегрировать их в процесс сборки (в частности, вам необходимо скомпилировать с Clang), что делает их первоначальную настройку намного сложнее, чем * grind, но, с другой стороны, они имеют гораздо меньшие накладные расходы времени выполнения.
Все перечисленные инструменты работают на Linux, а некоторые на MacOS. Я не думаю, что какая-либо работа над Windows пока надежна.
источник
Кажется, что большинство ответов здесь ошибочно принимают этот вопрос как «как автоматически определять условия гонки?» когда вопрос действительно "как мне воспроизвести условия гонки при тестировании, когда я их найду?"
Способ сделать это - ввести синхронизацию в ваш код, который используется только для тестирования. Например, если условие гонки происходит, когда событие X происходит между событием A и событием B, то для тестирования приложения напишите некоторый код, который ожидает события X после события A. Скорее всего, вам понадобится какой-то способ, чтобы ваши тесты могли поговорить с вашим приложением («эй, я тестирую эту вещь, так что ждите этого события в этом месте»).
Я использую node.js и mongo, где некоторые действия включают создание согласованных данных в нескольких коллекциях. В этих случаях мои модульные тесты будут вызывать приложение, чтобы сказать ему «настроить ожидание события X», и после того, как приложение установит его, будет запущен тест для события X, а затем тесты сообщат приложение («Я закончил с ожиданием события X»), поэтому остальные тесты будут работать нормально.
Ответ здесь подробно объясняет этот тип вещей в контексте Python: https://stackoverflow.com/questions/19602535/how-can-i-reproduce-the-race-conditions-in-this-python-code- надежно
источник