Стан гонитви
Стан гонитви (англ. race condition, race hazard) — помилкова ситуація під час виконання програми, в якій робота системи чи результат операції залежить від того, в якій послідовності, або ж з якою тривалістю виконуються окремі інструкції коду.
Стан гонитви є специфічною помилкою проектування системи, трапляється в багатопотокових і розподілених програмах. Проявляється неконтрольовано у випадкові моменти часу і досить часто симптоми стану гонитви зникають, якщо спробувати її злокалізувати.
Свою назву отримала від схожої помилки проектування електронних схем та поняття «перегонів сигналів».
Програмне забезпечення
Стани гонитви проявляються в застосунках, де окремі процеси або потоки виконання залежать від одного спільного стану. Дії над спільним станом є критичними секціями, що мають бути несумісними. Невдача в цьому призводить до можливості пошкодження спільного стану.
Стани гонитви горезвісно складні для відтворення і зневадження, бо кінцевий результат не є детерміністичним і дуже залежить від відносного перебігу виконування процесів, що взаємодіють. Проблеми, що зустрічаються в готових системах можуть зникнути при запуску в режимі зневадження, коли відбувається додаткове журналювання і перевіряння або коли приєднується зневаджувач. Часто такий стан називають гайзенбагом. Дуже радять уникати станів гонитви через уважне розробляння програми, а не через виправляння проблеми потім.
Приклад
Як простий приклад розглянемо два потоки, що хочуть збільшити на одиницю глобальну цілочисельну змінну. В ідеалі, потрібна така послідовність операцій:
Потік 1 | Потік 2 | Ціле | |
---|---|---|---|
0 | |||
прочитати | ← | 0 | |
збільшити | 0 | ||
записати | → | 1 | |
прочитати | ← | 1 | |
збільшити | 1 | ||
записати | → | 2 |
так ми отримаємо 2, як і очікували. Однак, якщо два потоки запустяться одночасно без блокування або синхронізації:
Потік 1 | Потік 2 | Ціле | |
---|---|---|---|
0 | |||
прочитати | ← | 0 | |
прочитати | ← | 0 | |
збільшити | 0 | ||
збільшити | 0 | ||
записати | → | 1 | |
записати | → | 1 |
Кінцеве значення 1, а не 2. Це станеться через те, що операції збільшення виконуються сумісно. несумісні дії — це такі, які не можна перервати під час доступу до деяких ресурсів, таких як пам'ять. У першому випадку, Потік 1 не переривали під час доступу до змінної, отже його операція була несумісною.
C++
Стандарт С++11 у параграфі 1.10 визначає стан гонитви так:
- Обчислення двох виразів конфліктує якщо один з виразів змінює ділянку пам'яті, а другий читає або також змінює ту саму ділянку пам'яті.
- Перебіг програми має стан гонитви, якщо він містить в різних потоках дві дії, що конфліктують, щонайменше одна з яких не атомарна і жодна не відбувається перед іншою.