Источники недетерминизма

Моя якобы детерминированная программа выдает один из нескольких слегка отличных результатов на разных прогонах. Вход, компилятор и компьютер неизменны. Я не уверен, какой вывод правильный, потому что он всегда выглядит разумным.

Помимо случайного вызова rand(), как это возможно?

12 ответов

Решение

Несколькими способами:

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

Мы, конечно, можем сделать больше предположений, но если вы хотите получить значимую помощь, возможно, было бы неплохо опубликовать соответствующие части вашего кода:-)

Если ваш вывод зависит от адреса, выделенного в куче:

int main(int argc, char* argv[])
{
   printf("%p", malloc(42));
   return 0;
}

Для каждого запуска malloc() может возвращать другой виртуальный адрес - не говоря уже о NULL в случае сбоя выделения.

Возможно:

  • Нить время
  • Любой вид ввода (пользователь, файл, сеть и т. Д.)

Если ваша программа использует float / double, результат может быть разным, если в какой-то архитектуре есть переключение контекста.

В x86 FPU использует расширенную точность для промежуточного результата, но при сохранении в памяти (что происходит при переключении контекста либо в процессе, либо в потоке) такая точность теряется. Это может привести к небольшому расхождению в результате (мы обнаружили такую ​​проблему в нашей программе). Один из способов избежать этой проблемы - попросить компилятор не использовать FPU, а SSE для операций с плавающей запятой.

http://www.network-theory.co.uk/docs/gccintro/gccintro_70.html

Помимо случайного вызова rand()

rand() является полностью детерминированным, если вы кормите его тем же начальным семенем.

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

Кроме того, попробуйте поискать условия гонки. Это может выглядеть недетерминированным.

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

В программах, которые не сильно взаимодействуют с "внешним миром", популярным источником недетерминизма является зависимость от указателя. Время от времени вы можете видеть это в коде: когда в лексикографической функции сравнения не хватает вещей для сравнения (все совпадают), она сравнивает адреса объектов как последнее средство. Это может привести к разным порядкам, если объекты размещены в динамической памяти, поскольку фактические места размещения могут различаться для разных платформ и для разных прогонов.

  • Входы из сети / интернета.
  • дата / время

Очевидно, новый экземпляр ошибки Phase of the Moon.

Вы не дали много информации. Однако, как человек, который занимается программированием в реальном времени для жизни, наиболее вероятные виновники, которых я ищу, когда такие вещи случаются:

  • Использование неинициализированной памяти.
  • Состояние гонки.
  • Некоторая неясная комбинация вышеперечисленного.

Например, одна такая проблема, с которой я когда-то сталкивался, заключалась в том, что разделяемая библиотека не была такой "общей", как я думал, и пыталась использовать дескриптор одного процесса для индексации таблицы, которая еще не была инициализирована во втором процессе. В зависимости от того, как все началось, что могло или не могло вызвать сбой важных данных в третьем процессе.

Любое неопределенное поведение. То есть: потребуются сотни страниц, чтобы объяснить все возможные источники изменения выходных данных. Попробуйте отладку, чтобы найти, где происходит изменение, или читайте некоторые спецификации C++.

Другие вопросы по тегам