c++multithreadingscheduler

C++ give Schedular hint to schedul to the next thread for std::thread


I have several threads working on different problems at the same time.

Sometimes some threads are waiting for the results of other threads, whose status is set by a boolean variable.

When a thread has to wait for the result of another thread, I do it like this:

while(!finished)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
}

I'm looking for a better way to signal the scheduler to proceed to the next thread. Something like this:

while(!finished)
{
    schedular.schedule();
}

What is the best way to signal to the scheduler that the current thread has nothing more to do and that it should continue with the next thread?


Solution

  • The approach you're currently using with std::this_thread::sleep_for introduces unnecessary delays and CPU usage, even with a small sleep duration. A better way to handle this scenario is to use synchronization primitives provided by the C++ Standard Library, such as std::condition_variable. These allow a thread to wait efficiently, yielding execution to the scheduler until it is notified.

    Using std::condition_variable

    Here’s how you can rewrite your code using std::condition_variable:

    #include <iostream>
    #include <thread>
    #include <condition_variable>
    #include <mutex>
    #include <atomic>
    
    std::atomic<bool> finished{false}; // Atomic variable for thread-safe status
    std::mutex mtx;                    // Mutex to protect condition variable
    std::condition_variable cv;        // Condition variable for signaling
    
    void worker_thread() {
        // Simulate some work
        std::this_thread::sleep_for(std::chrono::seconds(2));
    
        // Notify that the work is finished
        {
            std::lock_guard<std::mutex> lock(mtx);
            finished = true;
        }
        cv.notify_one(); // Notify waiting thread
    }
    
    void waiting_thread() {
        // Wait for the result
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return finished.load(); }); // Wait until finished is true
    
        std::cout << "Work is finished, proceeding..." << std::endl;
    }
    
    int main() {
        std::thread t1(worker_thread);
        std::thread t2(waiting_thread);
    
        t1.join();
        t2.join();
    
        return 0;
    }
    

    How It Works:

    1. Condition Variable (std::condition_variable):

      • The cv.wait method efficiently puts the thread to sleep and releases the lock on the mutex while waiting.
      • The thread is woken up only when cv.notify_one or cv.notify_all is called, reducing CPU usage compared to a busy-wait loop.
    2. Atomic Variable (std::atomic<bool>):

      • Ensures the finished flag is updated in a thread-safe manner without needing additional synchronization.
    3. Mutex (std::mutex):

      • Protects access to shared state (finished) and is required for std::condition_variable.

    Advantages:

    This pattern is the recommended approach when dealing with threads that depend on each other's results. It minimizes CPU usage and leverages the operating system's efficient thread scheduling mechanisms.