I wrote a wrote a program and it doesn't work as I expect it to.
I have two threads: thread
triggers func
and anotherThread
triggers anotherFunc
. What I wanted to do is when cont
reaches value 10
in func
, anotherThread
to be triggered using pthread_cond_wait
and pthread_cond_signal
. The strange thing is everything works fine if i uncomment the sleep(1)
line. I'm new to threads and I was following the tutorial here and if I comment the sleep
line in their example it breaks as well.
My question is how can I make this work without any sleep()
calls? And what happens if in my code both func
reaches pthread_mutex_lock
after anotherFunc
? How can I control these things? This is my code:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t myMutex;
pthread_cond_t cond;
pthread_attr_t attr;
int cont;
void *func(void*)
{
printf("func\n");
for(int i = 0; i < 20; i++)
{
pthread_mutex_lock(&myMutex);
cont++;
printf("%d\n", cont);
if(cont == 10)
{
printf("signal:\n");
pthread_cond_signal(&cond);
// sleep(1);
}
pthread_mutex_unlock(&myMutex);
}
printf("Done func\n");
pthread_exit(NULL);
}
void *anotherFunc(void*)
{
printf("anotherFunc\n");
pthread_mutex_lock(&myMutex);
printf("waiting...\n");
pthread_cond_wait(&cond, &myMutex);
cont += 10;
printf("slot\n");
pthread_mutex_unlock(&myMutex);
printf("mutex unlocked anotherFunc\n");
printf("Done anotherFunc\n");
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_t thread;
pthread_t anotherThread;
pthread_attr_init(&attr);
pthread_mutex_init(&myMutex, NULL);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_cond_init(&cond, NULL);
pthread_create(&anotherThread, &attr, anotherFunc, NULL);
pthread_create(&thread, &attr, func, NULL);
pthread_join(thread, NULL);
pthread_join(anotherThread, NULL);
printf("Done MAIN()");
pthread_mutex_destroy(&myMutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&attr);
pthread_exit(NULL);
return 0;
}
Sorry for the long post but I'm new to threads and I'm willing to learn. Also do you know some good references or courses/tutorials on threads and networking on Linux? I want to learn create an chat client and I heard that I have to know threads and networking for that. Problem is I don't know pretty good if what I learn is ok since I don't know what I have to know.
Thank you so much :)
Your anotherThread
simply calls pthread_cond_wait
without first testing whether the desired condition (counter reaching ten) has already happened. This is incorrect logic, which will lead to the lost wakeup problem: the name of a recurring bug that plagues incorrectly written multithreaded programs.
Condition variables are stateless. If pthread_cond_signal
or pthread_cond_broadcast
is called on a condition on which no threads are currently waiting, the operation has no effect. It is not remembered. So it is possible for your signaling thread to count to 10
very quickly, and signal the condition variable, before the other thread has reached the pthread_cond_wait
call.
You need a loop around pthread_cond_wait
. The condition must be checked in case it is already true, so that the thread does not wait for a wakeup which already happened. And it should be a loop because wakeups can be spurious: just because the thread falls through the pthread_cond_wait
doesn't mean that the condition is actually true:
while (cont < 10)
pthread_cond_wait(&cond, &myMutex);
Also, there is no need to create a thread attribute just to make a thread joinable. This is the default situation when you use a null pointer for the creation attribute. POSIX threads are joinable unless created detached, or converted to detached with pthread_detach
.
Another thing: whenever possible, avoid calling pthread_cond_signal
while holding a mutex lock. It's not incorrect, but it's potentially wasteful, because the operation may actually have to call into the OS kernel to wake up a thread, and so you're holding this expensive mutex lock over the entire system call (when all you really need it for is protecting a few machine instructions that working with shared data in your application).