Состояние гонки
Состоя́ние го́нки (англ. race condition) — ошибка проектирования многозадачной системы, при которой работа системы зависит от того, в каком порядке выполняются части кода. Название ошибка получила от похожей ошибки проектирования электронных схем (см. Гонки (электроника)).
Состояние гонки — специфический баг, проявляющийся в случайные моменты времени и «затихающий» при попытке его локализовать.
Пример
Рассмотрим пример кода (на Java)
volatile int x;
// Поток 1:
while (!stop)
{
x++;
…
}
// Поток 2:
while (!stop)
{
if (x%2 == 0)
System.out.println("x=" + x);
…
}
Пусть x=0. Предположим, что выполнение программы происходит в таком порядке:
- if в потоке 2 проверяет x на чётность.
- Оператор «x++» в потоке 1 увеличивает x на единицу.
- Оператор вывода в потоке 2 выводит «x=1», хотя, казалось бы, переменная проверена на чётность.
Способы решения
Локальная копия
Самый простой способ решения — копирование переменной x в локальную переменную. Вот исправленный код:
// Поток 2:
while (!stop)
{
int cached_x = x;
if (cached_x%2 == 0)
System.out.println("x=" + cached_x);
…
}
Естественно, этот способ работает только тогда, когда переменная одна и копирование производится за одну машинную команду.
Синхронизация
Более сложный, но и более универсальный метод решения — синхронизация потоков, а именно:
volatile int x;
// Поток 1:
while (!stop)
{
synchronized(SomeObject)
{
x++;
}
…
}
// Поток 2:
while (!stop)
{
synchronized(SomeObject)
{
if (x%2 == 0)
System.out.println("x=" + x);
}
…
}
Комбинированный способ
Предположим, что переменная x имеет тип не int
, а long
(на 32-битных ЭВМ её копирование выполняется за две машинных команды), а во втором потоке вместо System.out.println
стоит более сложная обработка. В этом случае оба метода неудовлетворительны: первый — потому что x может измениться, пока идет копирование; второй — потому что засинхронизирован слишком большой объём кода.
Эти способы можно скомбинировать, копируя «опасные» переменные в синхронизированном блоке. С одной стороны, это снимет ограничение на одну машинную команду, с другой — позволит избавиться от слишком больших синхроблоков.
volatile long x;
// Поток 1:
while (!stop)
{
synchronized(SomeObject)
{
x++;
}
…
}
// Поток 2:
while (!stop)
{
long cached_x;
synchronized (SomeObject)
{
cached_x = x;
}
if (cached_x%2 == 0)
//System.out.println("x=" + cached_x);
DoSomethingComplicated(cached_x);
…
}
Очевидных способов выявления и исправления состояний гонки не существует. Лучший способ избавиться от гонок — правильное проектирование многозадачной системы.
Случай с Therac-25
Аппарат лучевой терапии Therac-25 был первым в США медицинским аппаратом, в котором вопросы безопасности были возложены исключительно на программное обеспечение. Этот аппарат работал в трёх режимах:
- Электронная терапия: электронная пушка напрямую облучает пациента; компьютер задаёт энергию электронов от 5 до 25 МэВ.
- Рентгеновская терапия: электронная пушка облучает вольфрамовую мишень, и пациент облучается рентгеновскими лучами, проходящими через конусообразный рассеиватель. В этом режиме энергия электронов одна: 25 МэВ.
- В третьем режиме никакого излучения не было. На пути электронов (на случай аварии) располагается стальной отражатель, а излучение имитируется светом. Этот режим применяется для того, чтобы точно навести пучок на больное место.
Эти три режима задавались вращающимся диском, в котором было отверстие с отклоняющими магнитами для электронной терапии, и мишень с рассеивателем для рентгеновской. Из-за состояния гонки между управляющей программой и обработчиком клавиатуры иногда случалось, что в режиме рентгеновской терапии диск оказывался в положении «Электронная терапия», и пациент напрямую облучался пучком электронов в 25 МэВ, что вело к переоблучению. При этом датчики выводили «Нулевая доза», поэтому оператор мог повторить процедуру, усугубляя ситуацию. В результате погибли четыре пациента.
Часть кода была взята из Therac-6 и Therac-20. При этом в Therac-6 не было электронной терапии, а в Therac-20 были аппаратные меры безопасности, которые не давали включить излучение, когда диск в неправильном положении.
Взломы путём эксплуатирования состояния гонки
Существует класс ошибок (и эксплуатирующих их типов атак), позволяющих непривилегированной программе влиять на работу других программ через возможность изменения общедоступных ресурсов (обычно — вре́менных файлов; англ. /tmp race — состояние гонки во вре́менном каталоге), в определённое временно́е окно, в которое файл по ошибке программиста доступен для записи всем или части пользователей системы.
Атакующая программа может разрушить содержимое файла, вызвав аварийное завершение программы-жертвы, или, подменив данные, заставить программу выполнить какое-либо действие на уровне своих привилегий.
Именно по этой причине ПО с серьезными требованиями по безопасности, такое, как веб-браузер, использует случайные числа криптографического качества для именования временных файлов.
См. также
Ссылки
Компьютер | Это незавершённая статья о компьютерах. Вы можете помочь проекту, исправив и дополнив её. |
cs:Souběh de:Race Condition en:Race condition es:Condición de carrera fr:Situation de compétition he:מירוץ תהליכים it:Race condition ja:競合状態 ko:경쟁 상태 lt:Lenktynių aplinka pl:Hazard (elektronika) pt:Condição de corrida simple:Race condition zh:競爭危害
Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....