Let's imagine there is a thread which calls pthread_cond_wait and waits for signals:
pthread_mutex_lock(&m);
.....
while(run)
{
do {
pthread_cond_wait(&cond,&m);
} while(!got_signal);
got_signal = false;
do_something();
}
And there are multiple threads which are supposed to deliver signals:
pthread_mutex_lock(&m);
got_signal = true;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&m);
Is this solution safe enough? What will happen if multiple threads send signals? Does m mutex suffice to guarantee all signals are serialized and won't be lost?
In the code you posted, the only place where threads are allowed to call pthread_cond_signal() is when they can acquire m, and that can only happen when your waiting thread is blocked on pthread_cond_wait().
However, it might happen that two signaling threads acquire the mutex after each other, before the waiting thread is woken up and can acquire the mutex. In that case you'll lose the second signal (and any further signals that might arrive after that, before the waiting thread runs), since your waiting thread can only "see" that it has been signaled, but not how many times this has happened.
To make sure that you don't lose any signals, you could use a counter instead of your got_signal flag:
Waiting thread:
pthread_mutex_lock(&m);
.....
while(run)
{
while(signal_count == 0) {
pthread_cond_wait(&cond,&m);
}
--signal_count;
do_something();
}
Signaling threads:
pthread_mutex_lock(&m);
++signal_count;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&m);
(Also note that I've exchanged the do...whileloop with a while loop, to make sure that pthread_cond_wait() isn't called if there's still an unprocessed signal left.)
Now, if multiple threads end up signaling straight after each other, signal_count will become more than one, which will cause the waiting thread to run its do_something() multiple times instead of just once.
Related
Basic question but for the sake of briefness, I have two threads where bar unblocks foo upon a certain condition, but even though the program runs fine to my surprise, shouldn't it cause deadlock if foo is run first which acquires the lock which means bar shouldn't be able to proceed further given the condition variable would never be true in foo?
pthread_mutex_t lock;
pthread_cond_t cv;
bool dataReady = false;
void foo(void *arg)
{
printf ("Foo...\n");
pthread_mutex_lock(&lock);
while (!dataReady)
{
pthread_cond_wait(&cv, &lock);
}
printf ("Foo unlocked...\n");
dataReady = true;
pthread_mutex_unlock(&lock);
}
void bar(void *arg)
{
printf ("Bar...\n");
pthread_mutex_lock(&lock);
sleep(3);
printf ("Data ready...\n");
dataReady = true;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&lock);
}
int main(void)
{
int main()
{
pthread_t t1,t2;
pthread_create(&t1,NULL,foo,NULL);
pthread_create(&t2,NULL,bar,NULL);
pthread_join(t1,NULL);
pthread_join(t2,NULL);
return 0;
}
Also in this context, using semaphore wouldn't make sense yes?
pthread_cond_wait(&cv, &lock); atomically releases the mutex when called and the re-acquires it when woken up.
From man 3 pthread_cond_wait:
These functions atomically release mutex and cause the calling thread
to block on the condition variable cond; atomically here means
"atomically with respect to access by another thread to the mutex and
then the condition variable". That is, if another thread is able to
acquire the mutex after the about-to-block thread has released it,
then a subsequent call to pthread_cond_broadcast() or
pthread_cond_signal() in that thread shall behave as if it were issued
after the about-to-block thread has blocked.
Upon successful return, the mutex shall have been locked and shall be
owned by the calling thread.
IMHO C++ documentation contains clearer explanation (I know the languages differ, but the principle of operation remains the same):
https://en.cppreference.com/w/cpp/thread/condition_variable
acquire a std::unique_lockstd::mutex, on the same mutex as used to protect the shared variable
either
check the condition, in case it was already updated and notified
execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
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.
I know that:
If owner thread calls pthread_mutex_unlock, it will wake up a thread that is blocking on the mutex.
If owner thread calls pthread_cond_wait, it will atomically release the mutex and wait.
If owner thread wants to wake up one thread sleeping on its conditional variable, it will do pthread_cond_signal and pthread_mutex_unlock
Why do we need pthread_cond_signal if pthread_mutex_unlock itself can wake up those blocking threads?
pthread_cond_wait() blocks the calling thread until specific condition is signaled. This routine should be called while mutex is locked and it will automatically release the mutex while it waits. After a signal is received, the thread will be awakened and mutex will again be owned by the thread. Programmer needs to take care of unlocking mutex when thread is finished with it.
pthread_mutex_unlock(mutex) is used when thread has completed its use of protected data. When the programmer wants to unlock the mutex without any condition this should be used.
pthread_cond_signal (condition) is used to signal (or wake up) another thread which is waiting on the condition variable. This should be used only when one thread is to be woken from a blocking wait state. If more than one thread should be woken from blocking wait state than pthread_cond_broadcast(condition) should be used instead.
Why do we need pthread_cond_signal if pthread_mutex_unlock itself can
wake up those blocking threads?
Look at this code to understand your question :
void foo ()
{
for (i=0; i < TCOUNT; i++) {
pthread_mutex_lock(&count_mutex);
count++;
/*
Check the value of count and signal waiting thread when condition is
reached. Note that this occurs while mutex is locked.
*/
if (count == COUNT_LIMIT) {
pthread_cond_signal(&count_threshold_cv);
printf("inc_count(): thread %ld, count = %d Threshold reached.\n", my_id, count);
}
printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count);
pthread_mutex_unlock(&count_mutex);
}
/* Do some "work" so threads can alternate on mutex lock */
sleep(1);
}
void done ()
{
pthread_exit(NULL);
}
For pthread_mutex_lock() :
pthread_mutex_lock(&mutex);
str.mul *= mymul; /* Do some process on protected data */
pthread_mutex_unlock(&mutex);
In the first code, the mutex is unlocked by pthread_cond_signal() if the condition is satisfied.
In the second code, there is no condition directly mutex will be unlocked. In this type of case you can use pthread_mutex_unlock()
One more thing, sometimes pthread_cond_signal() fails to unlock the mutex; that is why mutex must be unlocked to complete the routine.
I am trying to better understand how to use pthread_cond_wait() and how it works.
I am just looking for a bit of clarification to an answer I saw on this site.
The answer is the last reply on this page
understanding of pthread_cond_wait() and pthread_cond_signal()
I am wondering how this would look with three threads. Imagine Thread 1 wants to tell Thread 2 and Thread 3 to wake up
For example
pthread_mutex_t mutex;
pthread_cond_t condition;
Thread 1:
pthread_mutex_lock(&mutex);
/*Initialize things*/
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 2 & 3
/*Do other things*/
Thread 2:
pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
pthread_cond_wait(&condition, &mutex); //wait for the condition
}
pthread_mutex_unlock(&mutex);
/*Do work*/
Thread 3:
pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
pthread_cond_wait(&condition, &mutex); //wait for the condition
}
pthread_mutex_unlock(&mutex);
/*Do work*/
I am wondering if such a setup is valid. Say that Thread 2 and 3 relied on some intialization options that thread 1 needs to process.
First: If you wish thread #1 to wake up thread #2 and #3, it should use pthread_cond_broadcast.
Second: The setup is valid (with broadcast). Thread #2 and #3 are scheduled for wakeup and they will try to reacquire the mutex as part of waking up. One of them will, the other will have to wait for the mutex to be unlocked again. So thread #2 and #3 access the critical section sequentically (to re-evaluate the condition).
If I understand correctly, you want thr#2 and thr#3 ("workers") to block until thr#1 ("boss") has performed some initialization.
Your approach is almost workable, but you need to broadcast rather than signal, and are missing a predicate variable separate from your condition variable. (In the question you reference, the predicate and condition variables were very similarly named.) For example:
pthread_mutex_t mtx;
pthread_cond_t cv;
int initialized = 0; // our predicate of interest, signaled via cv
...
// boss thread
initialize_things();
pthread_mutex_lock(&mtx);
initialized = 1;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
...
// worker threads
pthread_mutex_lock(&mtx);
while (! initialized) {
pthread_cond_wait(&cv, &mtx);
}
pthread_mutex_unlock(&mtx);
do_things();
That's common enough that you might want to combine the mutex/cv/flag into a single abstraction. (For inspiration, see Python's Event object.) POSIX barriers which are another way of synchronizing threads: every thread waits until all threads have "arrived." pthread_once is another way, as it runs a function once and only once no matter how many threads call it.
pthread_cond_signal wakes up one (random) thread waiting on the cond variable. If you want to wake up all threads waiting on this cond variable use pthread_cond_broadcast.
Depending what you are doing on the critical session there might be also another solution apart from the ones in the previous answers.
Suppose thread1 is executing first (i.e. it is the creator thread) and suppose thread2 and thread3 do not perform any write in to shared resource in the critical session. In this case with pthread_cond_wait you are forcing one thread to wait the other when actually there is no need.
You can use read-write mutex of type pthread_rwlock_t. Basically the thread1 performs a write-lock so the other threads will be blocked when trying to acquire a read-lock.
The functions for this lock are quite self-explanatory:
//They return: 0 if OK, error number on failure
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,
const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
When thread1 has finished its initialization it unlocks. The other threads will perform a read-lock and since more read-locks can co-exist they can execute simultaneously. Again: this is valid if you do not perform any write in thread2&3 on the shared resources.
Code:
void *inc_func(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&count_threshold_cv);
sleep(1);
pthread_mutex_unlock(&mutex);
}
void *watch(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&count_threshold_cv,&mutex);
sleep(1);
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t id[2];
pthread_create(&id[0],NULL,watch,NULL);
pthread_create(&id[1],NULL,inc_func,NULL);
int i;
for(i=0;i<2;i++)
pthread_join(id[i],NULL);
}
Now we have one mutex_unlock function to be executed in each thread. And one locked mutex. Why doesn't this lead to an undefined behaviour. Since both threads try to unlock the same mutex which leads to one trying to unlock an already unlocked mutex.
Edit: pthread_cond_wait releases the mutex for the second thread to use. Now consider the second thread executes pthread_cond_signal which leads to the first thread to reacquire the mutex. Now we have two threads having the same mutex lock,because both didn't get to execute the mutex_unlock because of the 'sleep' function. Is my understanding wrong?
pthread_mutex_lock() blocks if the mutex to be locked is already locked. It returns if the mutex got unlocked.
pthread_cond_wait() unlocks the mutex when starting to wait and locks is before returning. Returning might get delayed if the mutex in question is still locked. Returning then will be delay until the mutex got unlocked.
Putting the above together and applying it to the code you show one sees that each thread function nicely starts with a locking followed by an unlocking (and so on), so everything is fine.
Referring to the example code: pthread_cond_wait() returns when inc_func() had called pthread_mutex_unlock().
To successfully handle the scenario described by the example code you need to consider two special cases
the case of signal coming first and
the case of so called "spurious wake-ups", that is pthread_cond_wait() returning without having been signalled.
To handle both such case each condition should have a watch variable.
pthread_mutex_t mutex = ...
pthread_cond_t count_threshold_cv = ...
int signalled = 0;
void *inc_func(void *arg)
{
pthread_mutex_lock(&mutex);
pthread_cond_signal(&count_threshold_cv);
signalled = 1;
pthread_mutex_unlock(&mutex);
}
void *watch(void *arg)
{
pthread_mutex_lock(&mutex);
while (0 == signalled)
{
pthread_cond_wait(&count_threshold_cv,&mutex);
}
pthread_mutex_unlock(&mutex);
}
int main(void)
{
pthread_t id[2];
pthread_create(&id[0],NULL,watch,NULL);
pthread_create(&id[1],NULL,inc_func,NULL);
int i;
for(i=0;i<2;i++)
pthread_join(id[i],NULL);
}
If indeed the order is
watch runs first and locks (while inc_func waits)
watch which has the mutex waits using pthread_cond_wait which unlocks the mutext and blocks as per the documentation
These functions atomically release mutex and cause the calling thread
to block on the condition variable cond;
This allows the following
inc_func acquires the mutex then signals (at this point the mutex is yet to be released)
inc_func releases the mutex
Because the mutex was released and the mutex unlocked the execution of watch resumes having locked the mutex as per the documentation:
Upon successful return, the mutex has been locked and is owned by the calling thread.
What follows is a legal release of the mutex.
The scenario that you did not consider is what if the code of inc_func executes first without switching to watch
inc_func locks the mutex
inc_func signals but there's no one to be signaled, which is OK.
inc_func unlocks the mutex
watch locks the mutex
then waits for the conditional variable but there will be no one to signal it so it'll wait forever.
I am trying to learn basics of pthread_cond_wait. In all the usages, I see either
if(cond is false)
pthread_cond_wait
or
while(cond is false)
pthread_cond_wait
My question is, we want to cond_wait only because condition is false. Then why should i take the pain of explicitly putting an if/while loop. I can understand that without any if/while check before cond_wait we will directly hit that and it wont return at all. Is the condition check solely for solving this purpose or does it have anyother significance. If it for solving an unnecessary condition wait, then putting a condition check and avoiding the cond_wait is similar to polling?? I am using cond_wait like this.
void* proc_add(void *name){
struct vars *my_data = (struct vars*)name;
printf("In thread Addition and my id = %d\n",pthread_self());
while(1){
pthread_mutex_lock(&mutexattr);
while(!my_data->ipt){ // If no input get in
pthread_cond_wait(&mutexaddr_add,&mutexattr); // Wait till signalled
my_data->opt = my_data->a + my_data->b;
my_data->ipt=1;
pthread_cond_signal(&mutexaddr_opt);
}
pthread_mutex_unlock(&mutexattr);
if(my_data->end)
pthread_exit((void *)0);
}
}
The logic is, I am asking the input thread to process the data whenever an input is available and signal the output thread to print it.
You need a while loop because the thread that called pthread_cond_wait might wake up even when the condition you are waiting for isn't reached. This phenomenon is called "spurious wakeup".
This is not a bug, it is the way the conditional variables are implemented.
This can also be found in man pages:
Spurious wakeups from the pthread_cond_timedwait() or
pthread_cond_wait() functions may occur. Since the return from
pthread_cond_timedwait() or pthread_cond_wait() does not imply
anything about the value of this predicate, the predicate should be
re-evaluated upon such return.
Update regarding the actual code:
void* proc_add(void *name)
{
struct vars *my_data = (struct vars*)name;
printf("In thread Addition and my id = %d\n",pthread_self());
while(1) {
pthread_mutex_lock(&mutexattr);
while(!my_data->ipt){ // If no input get in
pthread_cond_wait(&mutexaddr_add,&mutexattr); // Wait till signalled
}
my_data->opt = my_data->a + my_data->b;
my_data->ipt=1;
pthread_cond_signal(&mutexaddr_opt);
pthread_mutex_unlock(&mutexattr);
if(my_data->end)
pthread_exit((void *)0);
}
}
}
You must test the condition under the mutex before waiting because signals of the condition variable are not queued (condition variables are not semaphores). That is, if a thread calls pthread_cond_signal() when no threads are blocked in pthread_cond_wait() on that condition variable, then the signal does nothing.
This means that if you had one thread set the condition:
pthread_mutex_lock(&m);
cond = true;
pthread_cond_signal(&c);
pthread_mutex_unlock(&m);
and then another thread unconditionally waited:
pthread_mutex_lock(&m);
pthread_cond_wait(&c, &m);
/* cond now true */
this second thread would block forever. This is avoided by having the second thread check for the condition:
pthread_mutex_lock(&m);
if (!cond)
pthread_cond_wait(&c, &m);
/* cond now true */
Since cond is only modified with the mutex m held, this means that the second thread waits if and only if cond is false.
The reason a while () loop is used in robust code instead of an if () is because pthread_cond_wait() does not guarantee that it will not wake up spuriously. Using a while () also means that signalling the condition variable is always perfectly safe - "extra" signals don't affect the program's correctness, which means that you can do things like move the signal outside of the locked section of code.