Pawel
Pawel

Reputation: 169

Not all threads notified of condition_variable.notify_all()

I have following scenario:

condition_variable cv;
mutex mut;

// Thread 1:
void run() {
    while (true) {
        mut.lock();
        // create_some_data();
        mut.unlock();
        cv.notify_all();        
    }
}

// Thread 2
void thread2() {
    mutex lockMutex;
    unique_lock<mutex> lock(lockMutex);
    while (running) {
        cv.wait(lock);
        mut.lock();
        // copy data
        mut.unlock();
        // process data
    }
}

// Thread 3, 4... - same as Thread 2

I run thread 1 all the time to get new data. Other threads wait with condition_variable until new data is available, then copy it and do some work on it. Work perfomed by threads differs in time needed to finish, the idea is that threads will get new data only when they finished with the old one. Data got in meantime is allowed to be "missed". I don't use shared mutex (only to access data) because I don't want threads to depend on each other.

Above code works fine on Windows, but now I run it on Ubuntu and I noticed that only one thread is being notified when notify_all() is called and the other ones just hangs on wait(). Why is that? Does Linux require different approach for using condition_variable?

Upvotes: 2

Views: 2814

Answers (3)

Richard Hodges
Richard Hodges

Reputation: 69922

It's working by luck.

The mutex and the condition variable are two parts of the same construct. You can't mix and match mutexes and cvs.

try this:

void thread2() {
    unique_lock<mutex> lock(mut); // use the global mutex
    while (running) {
        cv.wait(lock);
        // mutex is already locked here
        // test condition. wakeups can be spurious
        // copy data
        lock.unlock();
        // process data

        lock.lock();
    }
}

Upvotes: 2

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275956

Your code exhibits UB immediately as it relocks the unique lock that the cv has relocked when it exits wait.

There are other problems, like not detecting spurious wakeups.

Finally cv notify all onky notified currently waiting threads. If a thread shows up later, no dice.

Upvotes: 3

Andrew Henle
Andrew Henle

Reputation: 1

Per this documentation:

Any thread that intends to wait on std::condition_variable has to

  1. acquire a std::unique_lock, on the same mutex as used to protect the shared variable
  2. execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
  3. When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.

This code

void thread2() {
    mutex lockMutex;
    unique_lock<mutex> lock(lockMutex);
    while (running) {

doesn't do that.

Upvotes: 1

Related Questions