Condition variables and mutex_unlock - c

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.

Related

Using conditional variables to unblock one thread but wouldn't mutex lock cause a deadlock?

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.

Why is another thread, say B running when pthread_mutex is being locked and unlocked inside thread A?

According to the man pages
pthread_mutex_lock locks the given mutex. If the mutex is currently unlocked, it becomes locked and owned by the calling thread, and
pthread_mutex_lock returns immediately. If the mutex is already locked by another thread, pthread_mutex_lock suspends the calling thread
until the mutex is unlocked.
What I understood is when line 3 executes the main thread has ownership of the mtx. It then performs its critcal region actions and then reaches line 4 and unlocks mtx. My question is -
Can the other thread concurrently run when mtx is locked?
What is the use of line 2 since newThread can only unlock mtx when line 4 has been executed, and thus makes line 2 redundant?
What would happen if line 1 is uncommented?
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<unistd.h>
sem_t bin_sem;
pthread_mutex_t mtx;
char message[100];
void * thread_function(void * arg)
{
int x;
char message2[10];
while(1)
{
// pthread_mutex_lock(&mtx); //line 1
printf("thread2 : waiting..\n\n");
sem_wait(&bin_sem);
printf("hi i am the new thread waiting inside critical..\n");
scanf("%s",message);
printf("You entered in newthread:%s\n\n",message);
sem_post(&bin_sem);
pthread_mutex_unlock(&mtx); //line 2
}
}
int main(void)
{
pthread_t athread;
pthread_attr_t ta;
char message2[10];
int x;
sem_init(&bin_sem,0,1);
pthread_mutex_init(&mtx,NULL);
pthread_attr_init(&ta);
pthread_attr_setschedpolicy(&ta,SCHED_RR);
pthread_create(&athread,&ta,thread_function,NULL);
while(1)
{
pthread_mutex_lock(&mtx); //line 3
printf("main waiting..\n\n");
sem_wait(&bin_sem);
printf("hi i am the main thread waiting inside critical..\n");
scanf("%s",message);
printf("You entered in main:%s\n\n",message);
sem_post(&bin_sem);
pthread_mutex_unlock(&mtx); //line 4
}
sleep(5);
}
A mutex is a mechanism for implementing critical sections.
Any code between pthread_mutex_lock(x) and pthread_mutex_unlock(x) calls will execute in only one thread at any given time. That's all.
So ...
1. Can the other thread concurrently run when mtx is locked?
If it didn't lock the mtx, then of course.
2. What is the use of line 2 since newThread can only unlock mtx when line 4 has been executed, and thus makes line 2 redundant?
The mutex becomes useless, and you also get UB since you're unlocking it in the thread that didn't lock it:
If the mutex type is PTHREAD_MUTEX_DEFAULT...
Attempting to unlock the mutex if it was not locked by the calling thread results in undefined behavior.
(By default you get mutex type PTHREAD_MUTEX_DEFAULT)
3. What would happen if line 1 is uncommented?
You get thread starvation, since the mutex is locked almost all the time and is immediately re-locked after unlocking (POSIX doesn't guarantee mutex fairness).
A POSIX semaphore does provide fairness in some cases (when you use SCHED_FIFO or SCHED_RR schedulers), but is heavier.
I don't quite understand what you're trying to achieve (the application looks contrived). In a real application there's probably some logical ordering to the actions that either thread needs to take. So if the semaphore works for you, I'd keep it at that and remove the mutex.

pthread_mutex_lock why not block the thread as usual

Recently I read some code about thread mutex, releated code is here:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_t thread;
void fn(void *arg)
{
3 pthread_mutex_lock(&mutex);
printf( "signal before\n" );
4 pthread_cond_signal(&cond);
printf( "signal after\n" );
pthread_mutex_unlock(&mutex);
}
int main()
{
int err1;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond,NULL);
1 pthread_mutex_lock(&mutex);
2 err1 = pthread_create(&thread, NULL, fn, NULL);
usleep(1);
pthread_cond_wait(&cond,&mutex);
printf( "main thread get signal\n");
pthread_mutex_unlock(&mutex);
pthread_join(thread, NULL);
pthread_mutex_destroy( &mutex );
pthread_cond_destroy( &cond );
}
In main thread, first I call pthread_mutex_lock function locks the mutex in num 1, after I create a child thread in num 2, and in the child thread start function void fn( void *arg) I call pthread_mutex_lock in num 3 again, In theory it should block until mutex (main thread) is freed, but why can it continue to execute code in num 4 in child thread ?
execute result:
gcc version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/c++/4.2.1
Apple LLVM version 7.3.0 (clang-703.0.31)
Target: x86_64-apple-darwin15.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Thanks very much.
The purpose of a condition variable is to permit threads to wait for things to happen in other threads. The problem with doing this with a mutex is that the following code doesn't work:
Acquire the lock that protects the shared state.
See if we need to wait, if so wait.
Oops. Now we're waiting while we hold the lock. So no other thread can change the shared state. So we'll wait forever. Let's try it again, this time releasing the lock:
Acquire the lock that protects the shared state.
If we need to wait, release the lock and wait.
Oops, we still have a problem. What if the thing we're waiting for happens after we release the lock but before we begin waiting? Again, we'll wait forever.
So we need an atomic "unlock and wait" function to make step 2 work. That's what pthread_cond_wait is. So the mutex is released while the thread is waiting.
The canonical use of pthread_cond_wait is:
pthread_mutex_lock(&mutex);
while (we_need_to_wait)
pthread_cond_wait(&cond, &mutex);
// possibly do some stuff while we still hold the mutex
pthread_mutex_unlock(&mutex);
Notice this allows us to decide to wait while we still hold the mutex, wait without holding the mutex, but have no window for a race condition where the mutex is released but we're not yet waiting.
By the way, it's extremely difficult to use a condition variable sanely any other way. So you really shouldn't attempt to use pthread_cond_wait in any other pattern until you have a rock solid understanding of how condition variables work. Make absolutely sure you always know precisely what you're waiting for and the thing you're waiting for is protected by the mutex that you pass to pthread_cond_wait.

Do `pthread_mutex_lock` and `pthread_cond_wait` wait on the same queue?

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.

pthread_cond_wait() waking up two threads at the same time

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.

Resources