Должен ли я позаботиться о гоночных условиях, которые почти наверняка не имеют шансов произойти?


52

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

Я получил много разных ответов на это, но некоторые люди говорят, что если это условие гонки статистической невозможности, не беспокойтесь об этом вообще, но другие говорили, что если есть даже 10 -53 % (я шучу вы не о числах, это то, что я слышал) о магии вуду, происходящей из-за состояния гонки, всегда получайте / снимайте блокировки в потоке, который в этом нуждается.

о чем ты думаешь? Это хорошая практика программирования для обработки состояния гонки в таких статистически невозможных ситуациях? или было бы совершенно ненужным или даже контрпродуктивным добавлять больше строк кода, чтобы препятствовать удобочитаемости?


21
Когда люди заявляют о таких шансах, почему никто не спрашивает об образовании человека, заявляющего это число? Вам нужно формальное образование в области статистики, прежде чем вы сможете подкрепить такое число.
Питер Б

27
Как физик, p <1E-140 означает p = 0. Не произойдет в этой вселенной. 0,00000000000000000000000000000000000000000000000000001% намного больше.
MSalters

15
Убедитесь, что это состояние гонки не может привести к тому, что кто-то добровольно сломает ваше приложение. Это может быть причиной проблемы безопасности.
toasted_flakes

27
Один из миллиона шансов случается в девяти случаях из десяти.
Kaz Dragon

27
"почти наверняка не имеет шансов произойти?" означает, что это происходит в производстве в 3 часа ночи и, скорее всего, будет очень дорого.

Ответы:


137

Если это действительно событие типа 1 в 10 ^ 55, не было бы необходимости кодировать его. Это будет означать, что если вы выполняете операцию 1 миллион раз в секунду, вы будете получать одну ошибку каждые 3 * 10 ^ 41 года, что примерно в 10 ^ 31 раз больше возраста вселенной. Если ваше приложение имеет ошибку только один раз в каждом триллионе триллионов миллиардов возрастов вселенной, это, вероятно, достаточно надежно.

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


66
Мне вспоминается комментарий, который я прочитал несколько лет назад, но сейчас не могу найти: «Шанс 1 на миллион обычно следующий вторник». +1 за то, что он сказал, что "это далеко не так".
Беван

2
+1 за ставку. Лучший способ справиться с условиями гонки - это избавиться от них.
Blrfl

10
@Bevan «Шанс 1 на миллион обычно наступает в следующий вторник» ... если только вы не играете в лотерею :)
dasblinkenlight

22
@dasblinkenlight Но шансы кого - то победы в большинстве лотерей приближается к 100%. Прогнозировать кто , теперь это вызов.
Беван

3
@Bevan: Этот комментарий был именно тем, что приходило мне в голову, когда я читал вопрос - вот ссылка: blogs.msdn.com/b/larryosterman/archive/2004/03/30/104165.aspx
Док Браун

69

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

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

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


20
+1: для проведения различия между «неудачей, которая выглядит как неудача» и «неудачей, которая выглядит как успех». Неверная информация гораздо серьезнее, в зависимости от домена.
deworde

2
+1 это имеет большое значение, какими могут быть результаты состояния гонки.
Грант

+1 Последствия состояния гонки должны быть главным решающим фактором, если оно должно быть устранено. Состояние гонки, которое может привести к крушению самолета, сильно отличается от состояния, при котором пользователь может повторно открыть приложение.
тыкай

1
+1: я бы сказал, что последствия, вероятно, то, что вы должны анализировать, а не вероятность того, что это произойдет. Если последствия не имеют значения, вам, возможно, не придется обрабатывать состояние гонки ДАЖЕ, если оно очень распространено.
Лев

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

45

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

Что касается вероятностей, вы будете удивлены. В прошлом году у меня был отчет об ошибке состояния гонки, который я не мог воспроизвести с помощью тысяч автоматических попыток, но одна система одного клиента видела его постоянно. Экономическая целесообразность тратить 5 минут на ее устранение в настоящее время, в отличие от возможного устранения «невозможной» ошибки при установке клиента, делает выбор несложным.


1
Это тоже! Избегайте других программистов задуматься о возможных проблемах при чтении вашего кода, делая то, что необходимо (даже если «вряд ли» не получится).
Кейси Кубалл

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

2
+1 за указание на то, что вероятность состояния гонки, вероятно, зависит от многих факторов, поэтому, даже если это выглядит маловероятным в вашей конфигурации, это может происходить чаще в системе клиента / в другой ОС / в следующем выпуске и т. Д.
Слёске

27

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


6
+1 за изменение алгоритмов. Прямо сейчас, когда вы знаете о состоянии гонки, вероятности низкие. Через год, когда вы забыли о состоянии гонки, вы можете внести изменения в свой код, которые значительно изменят время и вероятность ошибки.
Фил

13

и какой-то другой поток опрашивает данные по сети или что-то, что гарантированно займет 5-10 секунд, чтобы завершить работу.

Пока кто-то не введет слой кэширования для повышения производительности. Внезапно, что другой шаг закончился почти мгновенно, и состояние гонки проявляется чаще, чем нет.

Если бы это произошло несколько недель назад, потребовалось около 2 дней на то, чтобы найти ошибку.

Всегда устанавливайте условия гонки, если вы их узнаете.


8

Простое против правильного.

Во многих случаях простота превосходит правильность. Это вопрос стоимости.

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

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


1
+1 для входа в систему и сбой рано, если исправить это слишком сложно.
Мартин Ба

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

@reirab Я не согласен. Если вы рассматриваете редкие события, то зарегистрированный сбой является экономически эффективным. Пример: если ваше телефонное приложение имеет частоту отказов 1/100 (сбой), если пользователь переключает сеть с точным переходом месяца (1/31 23:59:00 -> 2/1 00:00:00), вы вероятно, никогда не услышу об этом. Но тогда вероятность сбоя соединения с сервером на 1/10 ^ 9 недопустима. По-разному.
ptyx

7

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

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

Даже если у расы есть случайный случайный случай в 10 ^ (- 80) , вполне вероятно, что решительный злоумышленник имеет приличный шанс создать такие условия преднамеренно и искусственно.


6

Therac-25!

Разработчики проекта Therac-25 были довольно уверены в выборе времени между пользовательским интерфейсом и проблемой интерфейса в терапевтическом аппарате XRAY.

Они не должны были быть.

Вы можете узнать больше об этой известной программной катастрофе «жизнь и смерть» по адресу:

http://www.youtube.com/watch?v=izGSOsAGIVQ

или же

http://en.wikipedia.org/wiki/Therac-25

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

Если вы решили построить свой код так, чтобы он работал долго (и это звучит так, как будто вы это сделали), вам следует учитывать закон Мура, который может легко отбрасывать несколько нулей каждые несколько лет, поскольку компьютеры внутри или вне вашей системы работают быстрее. Если вы отправите тысячи копий, отбросьте больше нулей. Если пользователи выполняют эту операцию ежедневно (или ежемесячно) в течение многих лет, отнимите еще несколько. Если он используется там, где доступно волокно Google, что тогда? Если мусор UI собирает середину работы GUI, это влияет на гонку? Вы используете библиотеку с открытым исходным кодом или Windows за вашим графическим интерфейсом? Могут ли обновления там повлиять на время?

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

Я рекомендую вам явно синхронизировать, потому что, хотя вы, возможно, никогда не увидите, что это создает проблему, клиент может. Кроме того, даже если состояние вашей гонки никогда не наступит, что делать, если вы или ваша организация вызваны в суд для защиты вашего кода (поскольку Toyota была связана с Prius несколько лет назад). Чем тщательнее методология, тем лучше. Возможно, было бы лучше сказать «мы защищаемся от такого маловероятного случая, как этот ...», чем сказать «мы знаем, что наш код потерпит неудачу, но мы записали это уравнение, чтобы показать, что этого не произойдет при нашей жизни. Вероятно. "

Похоже, что расчет вероятности исходит от кого-то еще. Знают ли они ваш код, и знаете ли вы их достаточно, чтобы поверить, что ошибки не было? Если бы я вычислил надежность 99,99999% для чего-то, я мог бы также вспомнить свои занятия по статистике в колледже и вспомнить, что я не всегда получал 100%, и отбросил немало процентов на мои собственные оценки надежности.


1
+1 за упоминание Therac-25. Здесь много важных уроков.
Стюарт Маркс

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

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

4

Было бы совершенно ненужным или даже контрпродуктивным добавлять больше строк кода, чтобы затруднить читабельность?

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

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


3

Это будет зависеть от контекста. Если это обычная игра для iPhone, то, вероятно, нет. Система управления полетом для следующего пилотируемого космического корабля, вероятно. Все зависит от того, каковы будут последствия, если «плохой» результат будет измеряться в сравнении с предполагаемой стоимостью его исправления.

Для этих типов вопросов редко существует ответ «один размер подходит всем», потому что это не вопросы программирования, а вопросы экономики.


3
«Система управления полетом следующего пилотируемого космического корабля» ОПРЕДЕЛЕННО .
deworde

вероятно ... определенно ... это будет зависеть от того, кто был в ракете :-)
GrandmasterB

3

Да, ожидайте неожиданного. Я провел часы (в коде других людей ^^), отслеживая условия, которые никогда не должны происходить.

Такие вещи, как всегда есть else, всегда имеют значение по умолчанию для case, инициализируют переменные (да, действительно .. ошибки происходят из-за этого), проверяют ваши циклы на повторное использование переменных для каждой итерации и т. Д.

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


3

Просто исправь это.

Я видел именно это. Одному потоку удается выполнить сетевой запрос к серверу, который выполняет сложный поиск в базе данных и отвечает до того, как другой поток перешел к следующей строке кода. Такое случается.

Какой-то клиент где-нибудь решит однажды запустить что-то, что потребляет все процессорное время для «быстрого» потока, оставляя медленный поток запущенным, и вы пожалеете :)


1

Если вы узнали о маловероятном состоянии гонки, хотя бы запишите это в коде!

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


1
Да, и, по крайней мере, попытайтесь обнаружить это и зарегистрировать это, если это произойдет. ИМХО, это прекрасно, чтобы не избежать каждой ошибки. Но, по крайней мере, пусть кто-то знает, что это произошло, и что ваше предположение, что это не будет ошибочным.
Стив Беннетт

0

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


0

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

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


0

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

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

Receive event from device:
{
    Record event details.
    Enqueue event in the queuing thread.
    Acknowledge the event.
}

Queueing thread receives an event:
{
    Retrieve event details.
    Process event.
    Send next command to device.
}

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

Учитывая, что это затронуло только одного клиента в одной конфигурации, я постыдно указал, Thread.Sleep(1000)где была проблема. С тех пор проблем не было.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.