Sobes.tech
Middle

How can thread interaction be synchronized?

sobes.tech AI

Answer from AI

There are several main mechanisms for synchronization of interaction between threads in C/C++:

  • Mutexes: Provide exclusive access to a shared resource. A thread that has acquired a mutex blocks other threads from acquiring it until it releases the mutex.

    #include <mutex>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        my_mutex.lock(); // Acquire mutex
        // Work with shared resource
        my_mutex.unlock(); // Release mutex
    }
    

    Or using RAII:

    #include <mutex>
    #include <lock_guard>
    
    std::mutex my_mutex;
    
    void my_thread_function() {
        std::lock_guard<std::mutex> lock(my_mutex); // Acquire mutex upon object creation
        // Work with shared resource
        // Mutex will be automatically released when the lock object goes out of scope
    }
    
  • Semaphores: Generalization of mutexes. They maintain a counter that allows a specified number of threads to access a resource simultaneously.

    #include <semaphore.h> // For POSIX semaphores
    #include <windows.h> // For Windows semaphores
    
    sem_t my_semaphore; // POSIX semaphore
    
    void my_thread_function() {
        sem_wait(&my_semaphore); // Decrease semaphore counter, block if zero
        // Work with resource
        sem_post(&my_semaphore); // Increase semaphore counter
    }
    

    (Note: Standard C++ does not include semaphores directly, but they are available through system libraries or third-party implementations.)

  • Condition Variables: Used for a thread to wait for a certain condition to occur, releasing the mutex during the wait. Another thread can notify the waiting thread when the condition is met.

    #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; }); // Wait for condition
        // Condition met, work with resource
    }
    
    void notifying_thread() {
        std::unique_lock<std::mutex> lock(my_mutex);
        condition_met = true;
        lock.unlock(); // Optionally unlock before notifying
        my_cv.notify_one(); // Notify one waiting thread
        // or
        // my_cv.notify_all(); // Notify all waiting threads
    }
    
  • Atomic Operations: Allow performing simple operations on variables (e.g., increment, decrement) as a single, indivisible action without explicit mutex locking.

    #include <atomic>
    
    std::atomic<int> counter(0);
    
    void my_thread_function() {
        counter++; // Atomic increment
        // Or:
        // counter.fetch_add(1);
    }
    
  • Read-Write Locks (Shared Mutexes): Allow multiple threads to read data simultaneously, but only one thread to write data.

    #include <shared_mutex> // C++17 and above
    
    std::shared_mutex my_shared_mutex;
    
    void read_thread() {
        my_shared_mutex.lock_shared(); // Acquire for reading
        // Read data
        my_shared_mutex.unlock_shared(); // Release for reading
    }
    
    void write_thread() {
        my_shared_mutex.lock(); // Acquire for writing (exclusive)
        // Write data
        my_shared_mutex.unlock(); // Release for writing
    }
    
  • Barriers: Allow a group of threads to wait until all have reached a certain point in their execution before continuing.

    #include <barrier> // C++20
    
    std::barrier sync_point(4); // Barrier for 4 threads
    
    void my_thread_function() {
        // Work before barrier
        sync_point.arrive_and_wait(); // Wait until all threads reach the barrier
        // Work after barrier
    }
    

The choice of a specific mechanism depends on the nature of interaction and shared resources.