Hogyan lehet szinkronizálni a szálak közötti interakciót?
sobes.tech MI
Válasz az MI-től
A C/C++-ban több alapvető szinkronizációs mechanizmus létezik:
-
Mutekszok (Mutexek): Biztosítják a kizárólagos hozzáférést a megosztott erőforráshoz. Egy szál, amely megszerzi a mutexet, blokkolja a többi szálat, amíg el nem engedi.
#include <mutex> std::mutex my_mutex; void my_thread_function() { my_mutex.lock(); // Mutex megszerzése // Munka a megosztott erőforrással my_mutex.unlock(); // Mutex elengedése }Vagy RAII-val:
#include <mutex> #include <lock_guard> std::mutex my_mutex; void my_thread_function() { std::lock_guard<std::mutex> lock(my_mutex); // Mutex megszerzése az objektum létrehozásakor // Munka a megosztott erőforrással // A mutex automatikusan elengedésre kerül a hatókör végén } -
Szelep (Semaphore): A mutexek általánosítása. Számlálót tart fenn, amely lehetővé teszi, hogy egy adott számú szál egyidejűleg hozzáférjen a forráshoz.
#include <semaphore.h> // POSIX-szelephez #include <windows.h> // Windows-szelephez sem_t my_semaphore; // POSIX-szelep void my_thread_function() { sem_wait(&my_semaphore); // Csökkenti a számlálót, blokkol, ha 0 // Munka a forrással sem_post(&my_semaphore); // Növeli a számlálót }(Megjegyzés: A C++ szabvány nem tartalmaz közvetlenül szelep támogatást, de elérhető rendszerkönyvtárakon vagy harmadik féltől származó implementációkon keresztül.)
-
Feltételes változók (Condition Variables): Olyan mechanizmusok, amelyek lehetővé teszik, hogy egy szál várjon egy adott feltétel bekövetkeztére, miközben felszabadítja a mutexet. Egy másik szál értesítheti a várakozó szálat, hogy a feltétel teljesült.
#include <mutex> #include <condition_variable> std::mutex my_mutex; std::condition_variable my_cv; bool condition_met = false; void waiting_thread() { std::unique_lock<std::mutex> lock(my_mutex); my_cv.wait(lock, []{ return condition_met; }); // Várakozás a feltétel teljesülésére // A feltétel teljesült, munka a forrással } void notifying_thread() { std::unique_lock<std::mutex> lock(my_mutex); condition_met = true; lock.unlock(); // A mutex felszabadítása az értesítés előtt (ajánlott) my_cv.notify_one(); // Egy várakozó szál értesítése // vagy // my_cv.notify_all(); // Minden várakozó szál értesítése } -
Atomi műveletek (Atomic Operations): Lehetővé teszik egyszerű műveletek végrehajtását változókon (pl. növelés, csökkentés) egyetlen, oszthatatlan műveletként, explicit mutex zárás nélkül.
#include <atomic> std::atomic<int> counter(0); void my_thread_function() { counter++; // Atom növelés // Vagy: // counter.fetch_add(1); } -
Olvasási-Írási Lockok (Shared Mutexes): Lehetővé teszik több szálnak az adatok olvasását egyszerre, de csak egy szálnak írhatnak.
#include <shared_mutex> // C++17 és magasabb std::shared_mutex my_shared_mutex; void read_thread() { my_shared_mutex.lock_shared(); // Olvasási zárolás // Adatok olvasása my_shared_mutex.unlock_shared(); // Olvasási zárolás feloldása } void write_thread() { my_shared_mutex.lock(); // Írási zárolás (kizárólagos) // Adatok írása my_shared_mutex.unlock(); // Írási zárolás feloldása } -
Barikádok (Barriers): Lehetővé teszik egy csoport szálnak, hogy várjanak, amíg mind el nem érik egy adott pontot a végrehajtásukban, mielőtt folytatnák.
#include <barrier> // C++20 std::barrier sync_point(4); // Barikád 4 szál számára void my_thread_function() { // Munka a barikád előtt sync_point.arrive_and_wait(); // Várakozás, amíg minden szál el nem éri a barikádot // Munka a barikád után }
A konkrét mechanizmus kiválasztása a kölcsönhatás és a megosztott erőforrások jellemzőitől függ.