Hind Forsum
Hind Forsum

Reputation: 10527

"pthread_cond_wait" didn't wait main thread to sleep, why?

I did a simple experiment to test that:

  1. Main thread create a sub thread.
  2. Subthread wait main thread to signal the conditional variable.
  3. The main thread sleeps 3 seconds and signals the "cond". Then I expect that sub thread will wake up from "cond_wait" and print.

Code:

#include <pthread.h>
#include <unistd.h>
#include <cassert>
#include <iostream>

using namespace std;
pthread_mutex_t mt;
pthread_cond_t cond;
pthread_t tid;
void* tf(void*arg){
    pthread_mutex_lock(&mt);
    pthread_cond_wait(&cond, &mt);
    cout<<"After main thread sleeps 3 seconds\n";
    return NULL;
}
int main(){
    assert(0==pthread_mutex_init(&mt,NULL));
    pthread_create(&tid,NULL,tf,NULL);
    sleep(3);
    pthread_cond_signal(&cond);
    pthread_join(tid,NULL);//Is 2nd parameter useful?
    pthread_cond_destroy(&cond);
    return 0;
}

But in fact, the sub thread will print "After main thread sleeps 3 seconds" at once. Where did I get wrong?

Thanks.

Upvotes: 1

Views: 1134

Answers (2)

Curious
Curious

Reputation: 21560

Most importantly, since you attached the C++ tag to this question, use the C++ threading features, not the pthread library. You are not guaranteed to always have access to that (for example on windows), whereas std::thread is designed to be cross platform and free from some of the annoyances that come with using the pthread() library's C interface

Second, initialize your variables, C and C APIs are annoying like that. Third, you need to account for spurious wakeups, put a while loop around the condition variable wait, and attach an actual condition to it, for example

while (not_signalled) {
    pthread_cond_wait(&cond, &mt);
}

What might be happening is that your thread gets woken up spuriously and then finishes since you don't have a while loop protecting against spurious wakeups


Working C++ code

#include <thread>
#include <iostream>
#include <chrono>

using std::cout;
using std::endl;

std::mutex mtx;
std::condition_variable cv;
bool has_signalled{false};

void th_function() {
    // acquire the lock
    auto lck = std::unique_lock<std::mutex>{mtx};

    // loop to protect against spurious wakeups
    while (!has_signalled) {
        // sleep
        cv.wait(lck);
    }

    cout << "Thread has been signalled" << endl;
}

int main() {
    auto th = std::thread{th_function};

    // sleep for 2 seconds
    std::this_thread::sleep_for(std::chrono::seconds(2));

    // signal and change the variable
    {
        std::lock_guard<std::mutex> lck{mtx};
        has_signalled = true;
    }

    // signal
    cv.notify_one();

    th.join();
}

Upvotes: 4

Martin Rosenau
Martin Rosenau

Reputation: 18521

I'm not aware about the Linux threading functions but in Windows you would have to initialize the variable that corresponds to pthread_cond_t cond in Linux.

There is a manpage for a function named pthread_cond_init which seems to do exactly that.

Upvotes: 1

Related Questions