Что может вызвать недетерминированный вывод в программе? - PullRequest
0 голосов
/ 06 июня 2009

У меня ошибка в многопроцессорной программе. Программа получает входные данные и мгновенно выдает выходные данные без участия сети и не имеет ссылок на время. Что делает причину этой ошибки трудно отследить, так это то, что она возникает только иногда .

Если я постоянно запускаю его, он выдает как правильный, так и неправильный вывод, без видимого порядка или шаблона.

Что может вызвать такое недетерминированное поведение? Существуют ли инструменты, которые могут помочь? Существует вероятность того, что в игре присутствуют неинициализированные переменные. Как мне их найти?

РЕДАКТИРОВАТЬ: Проблема решена, спасибо всем, кто предложил Состояние гонки . Я не думал об этом главным образом потому, что был уверен, что мой дизайн предотвращает это. Проблема заключалась в том, что я использовал «wait» вместо «waitpid», поэтому иногда, когда некоторым процессам посчастливилось завершить работу раньше, чем я ожидал, правильный порядок вещей стал диким.

Ответы [ 7 ]

5 голосов
/ 06 июня 2009

Вы говорите, что это «многопроцессная» программа - не могли бы вы быть более конкретным? Вполне возможно, что вы столкнетесь с тем, как вы справляетесь с несколькими процессами.

Если бы вы могли рассказать нам больше о том, как взаимодействуют процессы, мы могли бы предложить некоторые возможности. Обратите внимание, что хотя предложение Артема об использовании отладчика само по себе прекрасно, вы должны знать, что введение отладчика вполне может изменить ситуацию полностью - особенно когда дело касается условий гонки. Лично я очень люблю регистрироваться, но даже это может незаметно изменить время.

3 голосов
/ 06 июня 2009

Скорее всего, вы смотрите на состояние гонки , то есть непредсказуемое и поэтому трудно воспроизводимое и отлаживаемое взаимодействие между неправильно синхронизированными потоками или процессами.

Недетерминизм в этом случае проистекает из планирования процесса / потока и доступа к памяти. Это непредсказуемо, поскольку на него влияет большое количество внешних факторов, включая сетевой трафик и ввод данных пользователем, которые постоянно вызывают прерывания и приводят к различным фактическим последовательностям выполнения в потоках программы при каждом запуске.

3 голосов
/ 06 июня 2009

Планировщик!

По сути, если у вас есть несколько процессов, они могут запускаться в любом странном порядке. Если эти процессы совместно используют ресурс, из которого они одновременно читают и пишут (будь то файл, память или какое-либо устройство ввода-вывода), операции будут чередоваться во всевозможных странных порядках. В качестве простого примера, предположим, что у вас есть два потока (они являются потоками, поэтому они совместно используют память), и они оба пытаются увеличить глобальную переменную, x.

y = x + 1;
x = y

Теперь запустите эти процессы, но чередуйте код таким образом

Предположим, х = 1

P1:

y = x + 1

Так что теперь в P1, для переменной y, которая является локальной и находится в стеке, y = 2. Затем приходит планировщик и запускает P2

P2:

y = x + 1
x = y

x был все еще 1, входящий в это, таким образом, 1 был добавлен к этому и теперь x = 2

Затем P1 заканчивает

P1

x = y

и х по-прежнему 2! Мы увеличили x дважды, но получили только один раз. И поскольку мы не знаем , как это произойдет, это называется недетерминированным поведением.

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

2 голосов
/ 07 июня 2009

Начните с основ ... убедитесь, что все ваши переменные имеют значение по умолчанию и что вся динамическая память обнуляется, прежде чем ее использовать (т.е. используйте calloc, а не malloc). Должна быть опция компилятора, чтобы пометить это (если вы не используете какой-то непонятный компилятор).

Если это c ++ (я знаю, что предполагается форумом 'c'), бывают случаи, когда создание объектов и инициализация отстают от назначения переменных, которые могут вас укусить. Например, если у вас есть область, которая используется одновременно несколькими потоками (как в одиночном или глобальном var), это может вызвать проблемы:

if (! Foo) Foo tmp = new Foo ();

Если у вас есть несколько потоков, обращающихся к вышеупомянутому, первый поток находит foo = null и запускает создание и присваивание объекта, а затем возвращает. Другой поток приходит и находит foo! = Null, поэтому пропускает раздел и начинает использовать foo.

2 голосов
/ 06 июня 2009

Это может быть много вещей, утечки памяти, доступ к критическим разделам, незакрытые ресурсы, незакрытые соединения и т. Д. Есть только один инструмент, который может вам помочь - отладчик, или попробуйте проверить свой алгоритм и найти ошибку, или если вы удалось указать проблемную часть, вы можете вставить сюда фрагмент, и мы постараемся вам помочь.

1 голос
/ 06 июня 2009

Нам нужно увидеть особенности вашего кода, чтобы иметь возможность дать более точный ответ, но чтобы быть кратким, когда у вас есть программа, которая координирует между несколькими процессами или несколькими потоками, переменная того, когда потоки выполняются, может добавить неопределенность в вашем приложении. По сути, планирование, которое выполняет ОС, может привести к тому, что процессы и потоки будут выполняться не по порядку. В зависимости от среды и кода планирование, которое выполняет ОС, может привести к совершенно разным результатам. Вы можете выполнить поиск в Google для получения дополнительной информации о выполнении вне очереди с многопоточностью для получения дополнительной информации; это большая тема.

0 голосов
/ 06 июня 2009

Под многопоточностью вы подразумеваете многопоточность? Если бы у нас было два потока, которые делают эту процедуру

i = 1;
while(true)
{
    printf(i++);
    if(i > 4) i = 1;
}

Обычно мы ожидаем, что результат будет примерно таким же, как

112233441122334411223344

Но на самом деле мы бы увидели что-то вроде

11232344112233441231423

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

Это пример состояния расы, упомянутого в других комментариях.

...