Как може да се синхронизира взаимодействието между нишки?
sobes.tech AI
Отговор от AI
Има няколко основни механизма за синхронизация и взаимодействие между нишки в C/C++:
-
Мютекси (Mutexes): Осигуряват изключителен достъп до споделен ресурс. Нишка, която е взела мютекса, блокира други нишки, опитващи се да го вземат, докато не го освободи.
#include <mutex> std::mutex my_mutex; void my_thread_function() { my_mutex.lock(); // Взимане на мютекса // Работа със споделения ресурс my_mutex.unlock(); // Освобождаване на мютекса }Или с RAII:
#include <mutex> #include <lock_guard> std::mutex my_mutex; void my_thread_function() { std::lock_guard<std::mutex> lock(my_mutex); // Взимане на мютекса при създаване // Работа със споделения ресурс // Мютексът автоматично се освобождава при изход от обхвата } -
Семафори (Semaphores): Обобщение на мютексите. Поддържа брояч, който позволява на определен брой нишки да имат достъп до ресурса едновременно.
#include <semaphore.h> // За POSIX семафори #include <windows.h> // За Windows семафори sem_t my_semaphore; // POSIX семафор void my_thread_function() { sem_wait(&my_semaphore); // Намалява брояча на семафора, блокира ако е 0 // Работа с ресурса sem_post(&my_semaphore); // Увеличава брояча на семафора }(Забележка: Стандартът C++ не включва директно семафори, но те са достъпни чрез системни библиотеки или външни реализации.)
-
Условни променливи (Condition Variables): Използват се за това, че нишка може да очаква настъпването на определено условие, като същевременно освобождава мютекса. Друга нишка може да уведоми чакащата, че условието е изпълнено.
#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; }); // Чакане за изпълнение на условието // Условието е изпълнено, работа с ресурса } void notifying_thread() { std::unique_lock<std::mutex> lock(my_mutex); condition_met = true; lock.unlock(); // Освобождаване на мютекса преди уведомяване (препоръчително) my_cv.notify_one(); // Уведомяване на един чакащ поток // или // my_cv.notify_all(); // Уведомяване на всички чакащи потоци } -
Атомарни операции (Atomic Operations): Позволяват изпълнението на прости операции върху променливи (например, инкремент, декремент) като едно неделимо действие, без необходимост от явен блокиращ механизъм.
#include <atomic> std::atomic<int> counter(0); void my_thread_function() { counter++; // Атомарен инкремент // Или: // counter.fetch_add(1); } -
Четене-писане заключвания (Shared Mutexes): Позволяват на няколко нишки да четат данни едновременно, но само на една да пише.
#include <shared_mutex> // C++17 и нагоре std::shared_mutex my_shared_mutex; void read_thread() { my_shared_mutex.lock_shared(); // Взимане за четене // Четене на данни my_shared_mutex.unlock_shared(); // Освобождаване за четене } void write_thread() { my_shared_mutex.lock(); // Взимане за писане (ексклузивно) // Писане на данни my_shared_mutex.unlock(); // Освобождаване за писане } -
Бариери (Barriers): Позволяват на група нишки да чакат, докато всички достигнат определена точка в изпълнението си, преди да продължат.
#include <barrier> // C++20 std::barrier sync_point(4); // Бариера за 4 нишки void my_thread_function() { // Работа преди бариерата sync_point.arrive_and_wait(); // Очакване, докато всички нишки достигнат бариерата // Работа след бариерата }
Изборът на конкретен механизъм зависи от характера на взаимодействието и споделените ресурси.