PThread Mutex Not Working as Hoped - c

I'm using mutexes to try to restrict access to certain part of the codes to one thread, but instead of locking once and blocking the others, it seems to allow all threads to "lock". Following is my code, and then a section of the output showing that the code is not working.
//headers defined, etc
pthread_mutex_t queuemutex = PTHREAD_MUTEX_INITIALIZER;
// other code with various functions
int main(void) {
//unrelated code
threadinformation **threadArray = (threadinformation **)malloc( POOLSIZE * sizeof(threadinformation) );
int k;
for (k = 0; k < POOLSIZE; k++) {
pthread_t thread;
threadinformation *currentThread = (threadinformation *)malloc(sizeof(threadinformation));
currentThread->state = (int *)malloc(sizeof(int));
currentThread->state[0] = 0;
currentThread->currentWaiting = currentWaiting;
currentThread->number = k;
threadArray[k] = currentThread;
pthread_create(&thread, NULL, readWriteToClient, threadArray[k]); //thread is created here
currentThread->thread = thread;
joinArray[k] = thread;
}
//unrelated code
}
static void* readWriteToClient(void *inputcontent) {
while(1){
//unrelated code
pthread_mutex_lock(&queuemutex); //problem happens here
fprintf(stderr,"Thread %d got locked \n",threadInput->number);
while((threadInput->currentWaiting->status) == 0){
pthread_cond_wait(&cond, &queuemutex);
fprintf(stderr,"Thread %d got signalled \n",threadInput->number);
}
connfd = threadInput->currentWaiting->fd;
threadInput->currentWaiting->status = 0;
pthread_cond_signal(&conncond);
pthread_mutex_unlock(&queuemutex);
//unrelated code
}
}
Output.
Thread 0 got locked
Thread 7 got locked
Thread 25 got locked
Thread 97 got locked
Thread 6 got locked
Thread 5 got locked
Thread 4 got locked
Thread 3 got locked
Thread 8 got locked
Thread 9 got locked
Thread 10 got locked
Thread 11 got locked
Thread 12 got locked
Thread 13 got locked
Thread 14 got locked
Thread 15 got locked
Thread 16 got locked
Thread 17 got locked
Thread 18 got locked
Thread 19 got locked
Thread 20 got locked
And so on...

There is no problem.
pthread_cond_wait(&cond, &queuemutex);
waiting on a condition variable RELEASES the mutex.

The longer version of what fceller said is that, pthread_cond_wait(&cond, &mutex) does three things before it returns: It releases the lock, and then it waits for a signal, and then it waits (if necessary) to re-acquire the lock.
Your example does not show what (if anything) ever sends the first signal, and it does not show what (if anything) ever sets the status that the worker threads are waiting for.
Here is a more typical use-case for pthread_cond_wait() and pthread_cond_signal().
void producer() {
pthread_mutex_lock(&mutex);
push_something_on_the_queue();
ptherad_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
void consumer() {
pthread_mutex_lock(&mutex);
while (! time_to_quit) {
if (queue_is_empty) {
pthread_cond_wait(&cond, &mutex);
} else {
thing = take_something_from_the_queue();
pthread_mutex_unlock(&mutex);
do_something_with(thing);
pthread_mutex_lock(&mutex);
}
}
pthread_mutex_unlock(&mutex);
}
A producer thread puts things in a queue. A consumer thread waits for things to appear in the queue, and then it pops them off and does something with them. The consumer waits in a loop, and it checks the status of the queue each time it wakes up (A thread may be "falsely" signalled even when there is nothing in the queue).
The mutex is locked when the consumer is checking the queue, and it remains locked until the consumer either sleeps or pops a thing off the queue. The mutex is not locked while the consumer is sleeping, and it is not locked while the consumer is doing whatever it does with a thing.
Any number of consumers can be in the consumer() method at the same time. They may be operating on different things, or they may be sleeping; but the mutex is insures that no more than one thread (producer or consumer) can touch the queue at any given time.

Related

Stop thread only if n threads are running including itself

I am requested to create some threads in a process(48), but thread number 14 must can stop only if 6 threads are running including itself. However they enter an infinite loop.
Here is the function my threads from the process should execute:
pthread_mutex_lock_t lock;
pthread_mutex_cond_t cond;
reached_6_threads = false;
void *thread_function_P6(void *args)
{
th *t = (th *)args;
printf("started thread %d", t->id);
if (t->id != 14)
{
pthread_mutex_lock(&lock);
while (th_no > 6)
{
pthread_cond_wait(&cond, &lock);
}
if(!reached_6_threads && th_no==6){
pthread_cond_wait(&cond, &lock);
th_no--;
reached_6_threads = true;
}
th_no++;
if (!reached_6_threads && th_no == 6)
{
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
}
printf("threads running: %d\n", th_no);
printf("stopped thread %d", t->id);
pthread_exit(0);
}
lock and cond are initrialized before creating the threads.
I am not sure I understand you, but note in your code that:
a) Most of the code is under mutex lock, which means they can't really run in parallel
b) Thread 14 runs regardless of the number of running threads
Anyway, the reason it gets stuck is:
a) Your threads are running almost sequentially
b) Threads 1-5 skip while and both ifs, th_no is now 5 (assuming it was initialized to 0?)
c) Thread 6 raises th_no to 6 and enters second if, performing broadcast but there are no threads stuck on that condition lock
d) Threads 7 and above enter first if and wait on a condition lock that will never break
I would suggest the following solution. Since I haven't understood you completely, in this example only 6 threads are allowed to run regardless of their id and you'll have to make only some minor changes.
pthread_mutex_lock(&lock);
while(th_no >= 6){pthread_cond_wait(&cond, &lock);}
th_no++;
pthread_mutex_unlock(&lock); //Raise counter and unlock the mutex
/*
Thread function code here. Pay attention to critical code and use mutex.
*/
pthread_mutex_lock(&lock); //Acquire lock once again, decrease counter and broadcast if number of threads is ok now
th_no--;
if(th_no <= 5){
if(pthread_cond_broadcast(&cond)){
// Error as it should return 0 on success
}
}
pthread_mutex_lock(&unlock);
Let me know if this helps

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.

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.

understanding pthread_cond_wait() and pthread_cond_signal()

I have this code as an example where two threads are created and then it looks like a pthread_cond_wait() is used to suspend that thread until it is ready to work again by the use of pthread_cond_signal(). My question is what if multiple threads are waiting at the same time? How will executing pthread_cond_signal() pick the correct thread to wake up? Is there a way to pick a specific thread to awake? Lets say i have a producer thread that puts customer orders into seperate queues where each queue is managed by a thread. If two consumer threads are suspend with wait() because they have nothing in their queue but then the producer thread only inserts an order into ONE of the consumer queues, how the heck do we differentiate? If this is not possible then what OTHER methods can i use to accomplish what i want?
Here is an example code because stackoverflow likes code... not that relevant:
Example
#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include "check.h"
/* For safe condition variable usage, must use a boolean predicate and */
/* a mutex with the condition. */
int workToDo = 0;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#define NTHREADS 2
void *threadfunc(void *parm)
{
int rc;
while (1) {
/* Usually worker threads will loop on these operations */
rc = pthread_mutex_lock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
while (!workToDo) {
printf("Thread blocked\n");
rc = pthread_cond_wait(&cond, &mutex);
checkResults("pthread_cond_wait()\n", rc);
}
printf("Thread awake, finish work!\n");
/* Under protection of the lock, complete or remove the work */
/* from whatever worker queue we have. Here it is simply a flag */
workToDo = 0;
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
}
return NULL;
}
int main(int argc, char **argv)
{
int rc=0;
int i;
pthread_t threadid[NTHREADS];
printf("Enter Testcase - %s\n", argv[0]);
printf("Create %d threads\n", NTHREADS);
for(i=0; i<NTHREADS; ++i) {
rc = pthread_create(&threadid[i], NULL, threadfunc, NULL);
checkResults("pthread_create()\n", rc);
}
sleep(5); /* Sleep is not a very robust way to serialize threads */
for(i=0; i<5; ++i) {
printf("Wake up a worker, work to do...\n");
rc = pthread_mutex_lock(&mutex);
checkResults("pthread_mutex_lock()\n", rc);
/* In the real world, all the threads might be busy, and */
/* we would add work to a queue instead of simply using a flag */
/* In that case the boolean predicate might be some boolean */
/* statement like: if (the-queue-contains-work) */
if (workToDo) {
printf("Work already present, likely threads are busy\n");
}
workToDo = 1;
rc = pthread_cond_signal(&cond);
checkResults("pthread_cond_broadcast()\n", rc);
rc = pthread_mutex_unlock(&mutex);
checkResults("pthread_mutex_unlock()\n", rc);
sleep(5); /* Sleep is not a very robust way to serialize threads */
}
printf("Main completed\n");
exit(0);
return 0;
}
Output:
Enter Testcase - QP0WTEST/TPCOS0
Create 2 threads
Thread blocked
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Wake up a worker, work to do...
Thread awake, finish work!
Thread blocked
Main completed
In practical terms, only one thread is awakened and you can't control which one it is.
(pthread_cond_signal wakes up at least one thread waiting on the given condition variable, and the thread chosen is determined by scheduling policy.)
In your case, you need to reconsider what the "condition" represented by your condition variable (condvar) means.
If the condvar truly means "a producer has added an item to one of several queues, each of which has a dedicated consumer," then you should pthread_cond_broadcast to awaken each queue's consumer and let the awakened threads figure out if there is work to do. Alternatively, you might recast the condition as "a producer has added an item to this queue, which has a dedicated consumer," and use one condvar per queue.

Resources