Ugrás a tartalomhoz

race condition

A Wikiszótárból, a nyitott szótárból


Főnév

race condition (tsz. race conditions)

  1. (informatika) versenyhelyzet

A race condition (magyarul: versenyhelyzet) egy hibás működést okozó állapot, amely párhuzamos (konkurens) programozás során fordul elő, amikor két vagy több szál vagy folyamat ugyanazt az erőforrást éri el vagy módosítja egy időben, és a végső eredmény az események időzítésétől függ. Ez kiszámíthatatlan, nem determinisztikus működéshez vezethet.



🧠 1. Mi az a race condition?

Egy race condition akkor következik be, ha:

  • két vagy több szál versenyez egy közös erőforrásért (pl. változó, fájl, memória),
  • nincs megfelelő szinkronizáció közöttük,
  • az események végrehajtási sorrendje befolyásolja az eredményt.

A versenyhelyzet hibák sokszor ritkán jelentkeznek, nehéz őket reprodukálni, és komoly biztonsági vagy logikai hibákhoz vezethetnek.


🧱 2. Példa egy versenyhelyzetre

C++ kód példa:

#include <thread>
#include <iostream>

int counter = 0;

void increment() {
    for (int i = 0; i < 100000; i++) {
        counter++;  // Nem szinkronizált
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    std::cout << "Counter: " << counter << std::endl;
    return 0;
}

Lehetséges eredmény:

Counter: 200000 helyett például Counter: 172485 – mivel a counter++ művelet nem atomi!



🔍 3. Mikor fordul elő?

  • Több szál (thread) vagy folyamat egy időben akar írni ugyanabba a változóba.
  • Hiányzik a mutex, semaphore, vagy más szinkronizációs mechanizmus.
  • Nem történik memóriahozzáférés sorbaállítás.
  • Nem atomi műveleteket hajtunk végre (pl. counter++ valójában több lépésből áll).



⏱ 4. Mik a következmények?

  • Helytelen működés: pl. pénz duplán levonódik egy tranzakció során.
  • Inkonzisztens állapot: pl. fájl részben módosul.
  • Ritkán jelentkező bugok, amelyeket nehéz teszteléssel elkapni.
  • Biztonsági rések: támadók is kihasználhatják (pl. race-to-check-to-use hibák).



🧩 5. Valós példák

🧾 Példa: banki átutalás

Két szál egyszerre ellenőrzi a számlaegyenleget és utal. Az egyik épp akkor olvas, amikor a másik már csökkentette az összeget, de még nem mentette el → dupla levonás vagy nem levont pénz.

🧪 Példa: fájlkezelés

  • check if file exists → majd open file
  • Közben másik folyamat törli/létrehozza a fájlt → race condition



🛠 6. Hogyan lehet elkerülni?

6.1. Mutex (Mutual Exclusion)

Biztosítja, hogy egyszerre csak egy szál hajthasson végre kódot egy kritikus szakaszban.

#include <mutex>
std::mutex m;

void increment() {
    for (int i = 0; i < 100000; i++) {
        std::lock_guard<std::mutex> lock(m);
        counter++;
    }
}

6.2. Szemafor (Semaphore)

Több szál összehangolt futtatására alkalmas, főleg több erőforrásnál.

6.3. Atomi műveletek

C++11 óta van std::atomic, amely biztosítja, hogy a művelet nem szakad meg közben:

#include <atomic>
std::atomic<int> counter(0);

6.4. Immutabilitás

Ha az adat nem módosul, akkor nincs versenyhelyzet.

6.5. Lock-free algoritmusok

Speciális technikák, ahol nincs zár, mégis helyes működés biztosított (pl. CAS – Compare and Swap).



🔐 7. Race condition és biztonság

A versenyhelyzetek biztonsági kockázatok forrásai is lehetnek:

  • TOCTOU (Time Of Check To Time Of Use): egy ellenőrzés és a használat közti időben a feltétel megváltozik.
  • Privilege escalation: pl. root jogú fájl ideiglenes megléte miatt.



🧪 8. Debugolás – hogyan ismerjük fel?

  • Valószínűségi hibák: nem mindig fordulnak elő.
  • Használhatók:
    • Valgrind / Helgrind
    • ThreadSanitizer
    • Intel Inspector
    • GDB race detection



🔁 9. Többszálú környezetben versenyhelyzetek forrásai

Forrás Lehetséges következmény
Globális változók Inkonzisztens állapot
I/O műveletek Elveszett vagy hibás adat
Memóriakezelés Dupla felszabadítás, use-after-free
Időzítés alapú műveletek Változó működés minden futtatáskor



⚙️ 10. Összegzés

A race condition az egyik legveszélyesebb hiba többszálú környezetben, mert:

  • nehezen észlelhető,
  • komoly következményekkel járhat,
  • sokféle módon felléphet.

Fontos elkerülési szabályok:

  • Használjunk mutexet minden közösen elérhető erőforrás körül.
  • Csak atomi műveletekkel módosítsunk globális változókat.
  • Tervezéskor gondoljunk a párhuzamosságra – ne utólag javítsuk.