pthread_mutex_lock why not block the thread as usual - c

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.

Related

Unlocking the condition variable mutex twice?

I'm looking at the following snippets:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cvar;
char buf[25];
void*thread_f(void *);
int main(){
pthread_t thr;
pthread_cond_init(&cvar,NULL);
pthread_mutex_lock(&mtx);
pthread_create(&thr,NULL,thread_f,NULL);
pthread_cond_wait(&cvar,&mtx);
pthread_mutex_unlock(&mtx);
...join and destroy thread...
}
and thread_f:
void* thread_f(void* argp){
pthread_mutex_lock(&mtx);
strcpy(buf,"test");
pthread_cond_signal(&cvar);
pthread_mutex_unlock(&mtx); //why?
pthread_exit(NULL);
}
My understanding of the above code is, that main grabs the lock, creates the thread and runs thread_f which blocks. Then, main signals the wait on the condition variable cvar and unlocks the mutex. Then, thread_f unblocks, strcpys and signals cvar to wake up. Then, both main and thread_f unlock the mutex.
Is this the actual behaviour, or am I missing something somewhere? If it's the actual behaviour, isn't unlocking the already unlocked mutex UB, therefore should one of he mutex unlocks in the end be removed?
Thanks.
What this code is doing is valid.
When the thread calls pthread_cond_signal it doesn't immediately cause the main thread to grab the mutex, but wakes up the main thread so it can attempt to lock it. Then once the thread releases the mutex, the main thread is able to lock it and return from pthread_cond_wait.
The pthread_cond_wait() in the main thread unlocks the mutex and waits for the condition to be signalled — and relocks the mutex before returning.
The child thread is able to lock the mutex, manipulate the buffer, signal the condition and then unlock the mutex, letting the main thread reacquire the lock.
Consequently, the code is well-behaved — give or take the need to worry about 'spurious wakeups' in more general situations with multiple child threads. I don't think you can get a spurious wakeup here.

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.

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.

Condition variables and mutex_unlock

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.

pthreads: cancel blocking thread

I have a situation like
-Thread A-
Lock Mutex
If ActionA() == ERROR
Stop = True
Unlock Mutex
-Mainthread-
Lock Mutex
If ActionB() == ERROR
Stop = True
If Stop == True
Cancel ThreadA
Join ThreadA
Exit program
Unlock Mutex
where a Mutex is used for synchronization. The worker thread 'Thread A' and the main thread can both get into an error state and set the local variable 'Stop' then, which should lead to the cancellation of Thread A and exit of the main program. The Mutex is used to prevent a race condition when accessing Stop (and other shared objects).
Unfortunately calling pthread_cancel() does not seem to work when the target thread is waiting for a Mutex:
#include <pthread.h>
pthread_mutex_t mutex;
void *thread(void *args){
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock(&mutex);
return NULL;
}
int main(int argc, const char * argv[])
{
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
pthread_t t;
pthread_create(&t, NULL, thread, NULL);
pthread_cancel(t);
pthread_join(t, NULL);
//Execution does not get here
}
Do you have any idea what I might try else?
Thank you in advance
pthread_mutex_lock() is just plain not a cancellation point where pthread_cancel() can cancel the thread; if you really need to break the thread, you need to find a way to release the mutex it's waiting for so it can reach a cancellation point (or, well, not use mutexes in the regions where it needs to be cancelled).
From the pthread_cancel() manual;
pthread_mutex_lock() is not a cancellation point, although it may block indefinitely; making pthread_mutex_lock() a cancellation point would make writing correct cancellation handlers difficult, if not impossible.

Resources