How to use mutexes in C - c

I am confused about use of multiple mutexes in C.
int main() {
pthread_t thread1;
char *message1 = "Thread 1";
int r;
pthread_mutex_init(&mutex1, NULL);
pthread_mutex_init(&mutex2, NULL);
pthread_mutex_lock(&mutex1);
r = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
printf("Parent 1\n");
pthread_mutex_lock(&mutex2);
printf("Parent 2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
pthread_join( thread1, NULL);
printf("Thread 1 returns: %d\n",r);
return 0;
}
void *print_message_function( void *str ) {
pthread_mutex_lock(&mutex1);
char *message;
message = (char *) str;
printf("Child 1 received message: %s \n", message);
pthread_mutex_lock(&mutex2);
printf("child 2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
output is
Parent 1
Parent 2
Child 1 received message: Thread 1
child 2
Thread 1 returns: 0
what i want is
Parent 1
Child 1 received message: Thread 1
Parent 2
child 2
Thread 1 returns: 0

When you call pthread_create you have already locked mutex1. That means that every other thread that calls pthread_mutex_lock(&mutex1); will wait for the mutex to be unlocked. That is what happen when you create a second thread: mutex1 is already locked, so the second thread cannot enter the critical section but need to wait for the mutex to be unlocked. That happens at the end of the main function.
You'll need to reorganize your code to get the output you desire.
However, to obtain such a result you should check synchronization systems, such semaphores or condition variables; they will provide a clearer and easier way to synchronize threads.
You may also check this tutorial: POSIX Threads Programming
A simple solution using semaphores (not tested, but it should work):
#include <stdio.h>
#include <semaphore.h>
sem_t sem1, sem2;
void* f(void* str) {
sem_wait(&sem1);
printf("Child 1 received message: %s \n",(char*)str);
sem_post(&sem2);
sem_wait(&sem1);
printf("Child 2\n");
return NULL;
}
int main (int argc, const char * argv[]) {
pthread_t thread;
char* message = "Thread 1";
int r;
sem_init(&sem1,0,0);
sem_init(&sem2,0,0);
r = pthread_create(&thread, NULL, f, (void*)message);
sem_post(&sem1);
sem_wait(&sem2);
printf("Parent 2\n");
sem_post(&sem1);
pthread_join(thread1, NULL);
printf("Thread 1 returns: %d\n",r);
return 0;
}

Mutexes alone aren't suitable for performing the kind of closely-interlocked execution that you want - their normal use is for protecting access to a shared data structure. This is because they're designed for saying "Thing A shouldn't happen at the same time as Thing B", but they don't say anything about whether Thing A or Thing B happens first or second.
You could use mutexes and condition variables, but in this case your problem is most closely matched by a pthreads Barrier object:
#include <stdio.h>
#include <pthread.h>
pthread_barrier_t barrier;
void *print_message_function( void *str )
{
char *message;
message = (char *) str;
pthread_barrier_wait(&barrier); /* Barrier point 1 */
/* (wait until parent prints first message) */
printf("Child 1 received message: %s \n", message);
pthread_barrier_wait(&barrier); /* Barrier point 2 */
/* (allow parent to proceed and print second message) */
pthread_barrier_wait(&barrier); /* Barrier point 3 */
/* (wait for parent to print second message) */
printf("child 2\n");
return NULL;
}
int main()
{
pthread_t thread1;
char *message1 = "Thread 1";
int r;
pthread_barrier_init(&barrier, NULL, 2);
r = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
printf("Parent 1\n");
pthread_barrier_wait(&barrier); /* Barrier point 1 */
/* (allow child to proceed and print first message) */
pthread_barrier_wait(&barrier); /* Barrier point 2 */
/* (wait for child to print first message) */
printf("Parent 2\n");
pthread_barrier_wait(&barrier); /* Barrier point 3 */
/* (allow child to proceed and print second message) */
pthread_join( thread1, NULL);
/* (wait for child to exit) */
printf("Thread 1 returns: %d\n",r);
return 0;
}
Note that it is not usual to try to tightly interlock the execution of threads in this way - really, you've gone to great pains to ensure that the threads don't execute in parallel at all, which is the whole point of threads in the first place. If you find yourself doing this in a real project, it's a sign that you ought to carefully re-think your design.

I think you need to unlock mutex1 sooner. You unlock it after the printf("Parent 2\n"); so thread1 is still locked waiting for pthread_mutex_lock(&mutex1);.
When thread1 starts it's first step is to lock while it waits for mutual exclusion (clue's in the name) lock on mutex1. So it's paused.
Then you :
printf("Parent 1\n");
pthread_mutex_lock(&mutex2); <-- lock 2 is unleased but thread one is waiting on mutex1
printf("Parent 2\n");

Related

Simple example for pthread_join deadlock

I am looking for a very simple example to demonstrate a deadlock using pthread_join; however, this is not trivial.
I started with this:
void* joinit(void* tid)
{
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
pthread_join(thread2, NULL);
return 0;
}
But however, it says 'EINVAL' (invalid argument) because thread2 is not yet specified when pthread_create for thread1 is called.
Any ideas?
If you're just wanting to demonstrate that a pthread_join can cause a deadlock, you could do something similar to the following code:
#include <stdio.h>
#include <pthread.h>
void* joinit(void* tid)
{
printf("In %#x, waiting on %#x\n", pthread_self(), (*((pthread_t*)tid)));
pthread_join((*((pthread_t*)tid)), NULL);
printf("Leaving %#x\n", pthread_self());
return NULL;
}
int main(void)
{
pthread_t thread1 = pthread_self();
pthread_t thread2;
pthread_create(&thread2, NULL, joinit, &thread1);
joinit(&thread2);
return 0;
}
This will cause the main thread to wait on the spawned thread and the spawned thread to wait on the main thread (causing a guaranteed deadlock) without the need for extra locking primitives to clutter up what you are trying to demonstrate.
And to answer some of your questions more directly:
it says 'EINVAL' (invalid argument) because thread2 is not yet specified when pthread_create for thread1 is called.
... and from one of your comments ...
I tried this and it worked, but the problem is, it only works SOMETIMES because sometimes I get EINVAL again.
In your code, you call pthread_create consecutively to spawn the 2 threads:
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
In your joinit code, you grab the thread handle passed in to join on:
pthread_t* tid_c = (pthread_t*)tid;
int retval = pthread_join(*tid_c, NULL);
The reason this sometimes works and others you'll get EINVAL has to do with time slices allocated to each thread's context and sequencing. When the first pthread_create is called you will have a valid handle to thread1 after it returns but the handle to thread2 is not valid yet, at least not until the 2nd pthread_create is called.
To this, when a thread is created, the act of the thread coming "alive" (i.e. the thread function actually running) could take some extra time even though the thread handle returned is valid. In these instances, there is a chance one thread can execute more code than might be "expected". In your code, both pthread_create functions might happen to have been called in the time slice allocated for the main thread which could give each spawned thread enough "time" before hitting the pthread_join statement allowing tid_c to point to a valid handle; in the EINVAL case, pthread_create(&thread1, NULL, joinit, &thread2) was called and the spawned thread hit the pthread_join(*tid_c, NULL) before pthread_create(&thread2, NULL, joinit, &thread1) could give thread2 a valid handle (causing the error).
If you wanted to keep your code similar to how it is now, you would need to add a lock of some sort to ensure the threads don't exit or call anything prematurely:
#include <stdio.h>
#include <pthread.h>
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void* joinit(void* tid)
{
/* this can be above the lock because it will be valid after lock is acquired */
pthread_t* tid_c = (pthread_t*)tid;
int retval = -1;
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
printf("%#x waiting on %#x\n", pthread_self(), *tid_c);
retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
return NULL;
}
int main()
{
pthread_t thread1;
pthread_t thread2;
/* get the lock in the main thread FIRST */
pthread_mutex_lock(&lock);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
/* by this point, both handles are "joinable", so unlock */
pthread_mutex_unlock(&lock);
/* can wait on either thread, but must wait on one so main thread doesn't exit */
pthread_join(thread2, NULL);
return 0;
}
Hope this can help.
The main reason for your error is that you have two threads each waiting for the same thread to terminate because of the call to pthread_join in main. Another problem is that you don't ensure each thread correctly sees the other thread's ID.
Fix it like this:
#include <stdio.h>
#include <pthread.h>
pthread_t thread1;
pthread_t thread2;
pthread_mutex_t mutex;
pthread_cond_t cond;
int go = 0;
void* joinit(void* ptr)
{
// wait until both thread IDs are known
pthread_mutex_lock(&mutex);
while (go == 0)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
pthread_t* tid_c = *((pthread_t**) ptr);
printf("About to wait\n");
int retval = pthread_join(*tid_c, NULL);
printf("In joinit: tid = %d, retval = %d \n", *tid_c, retval);
// tell the other threads we're done
pthread_mutex_lock(&mutex);
go++;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main()
{
// setup synchronization
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_create(&thread1, NULL, joinit, &thread2);
pthread_create(&thread2, NULL, joinit, &thread1);
// tell the threads to go
pthread_mutex_lock(&mutex);
go = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
// wait for both threads to finish
pthread_mutex_lock(&mutex);
while (go != 3)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
return 0;
}

Mutex Threading - Code doesn't seem to Exit Properly

So I have code here which makes two kinds of threads. One kind "produces" data and the other one "consumes" it. There can only be a certain amount of data that can exist at any one time, so the Producers will pause producing once there is a certain amount of data created (ie, when sharedData = BUFFER), and the consumers will pause when sharedData = 0. There is also only so much data that can be made (amount stored in dataleft), and once all the data has been made and consumed, the program should end.
For some reason, the printf() lines I have at the end of the code don't seem to ever trigger. I can't tell if the threads are closed properly or not because of this. It feels like I've done something really stupid, but I can't see the issue.
A couple of definitions at the start:
#define NUMCONSUMERS 4
#define NUMPRODUCERS 4
#define PACKETS 10
#define tryMainlock pthread_mutex_trylock(&dataMutex)
#define openMainlock pthread_mutex_lock(&dataMutex)
#define closeMainlock pthread_mutex_unlock(&dataMutex)
#define waitMainlock pthread_cond_wait(&dataPresentCondition, &dataMutex);
#define signalMainlock pthread_cond_signal(&dataPresentCondition);
#define trydatalock pthread_mutex_trylock(&IsthereDataleft)
#define opendatalock pthread_mutex_lock(&IsthereDataleft)
#define closedatalock pthread_mutex_unlock(&IsthereDataleft)
pthread_mutex_t dataMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dataPresentCondition = PTHREAD_COND_INITIALIZER;
pthread_mutex_t IsthereDataleft = PTHREAD_MUTEX_INITIALIZER;
int sharedData=0; //amount of data present
int BUFFER = 5;
int dataleft=PACKETS;
The Main Function:
int main(int argc, char **argv)
{
int rc;
int i;
pthread_t consumer[NUMCONSUMERS];
pthread_t producer[NUMPRODUCERS];
rc = opendatalock; //lock to determine whether there's any point waiting for data
for (i=0; i <NUMPRODUCERS; i++) { //Build up the producers
rc = pthread_create(&producer[i], NULL, Producer, (void *)i);
if (rc)
printf("Error building Producer Thread: %x\n", i);
}
for (i=0; i <NUMCONSUMERS; i++) { //Build up the consumers
rc = pthread_create(&consumer[i], NULL, Consumer, (void *)i);
if (rc)
printf("Error building Consumer Thread: %x\n", i);
}
printf("All Producers and Consumers created\n");
for (i=0; i <NUMPRODUCERS; i++) { //Join up the producers
rc = pthread_join(producer[i], NULL);
if (rc)
printf("Error: Producer %x: Failed to join\n", i);
}
rc = closedatalock; //producers finished, no data left to make
printf("datalock closed, consumers finishing...\n");
for (i=0; i <NUMCONSUMERS; i++) { //Join up the consumers
rc = pthread_join(consumer[i], NULL);
if (rc)
printf("Error: Consumer %x: Failed to join\n", i);
}
rc = pthread_mutex_destroy(&dataMutex);
rc = pthread_cond_destroy(&dataPresentCondition);
rc = pthread_mutex_destroy(&IsthereDataleft);
printf("All Threads finished. Exiting....\n");
return 0;
}
The Consumer Thread:
void *Consumer(void *threadid){
int rc;
printf("Consumer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Consumer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of main lock
if (rc)
{
printf("Consumer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //if main lock is taken, wait
if (rc) //if wait fails, exit the thread.
{
printf("Consumer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
while (sharedData == 0) //if the buffer is empty
{
rc = trydatalock;
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
sharedData--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Consumer %x: Releasing Lock\n", (int)threadid);
}
}
And the Producer Thread:
void *Producer(void *threadid){
int rc;
printf("Producer Thread %x: Created\n", (int)threadid);
while (1)
{
printf("Producer %x: Entering Loop\n", (int)threadid);
rc = openMainlock; //take hold of the lock
if (rc) //if lock is currently being used by a consumer or a producer
{
printf("Producer %x: Waiting...\n", (int)threadid);
rc = waitMainlock; //wait here until lock is released
if (rc)
{
printf("Producer Thread %x: wait for Main Lock failed\n", threadid);
exit(0);
}
}
if (!dataleft) //If there's no data left to add to the stream, close the thread
{
printf("Producer Thread %x: Completed, exiting...\n", (int)threadid);
exit(0);
}
while (sharedData >=BUFFER)
{
rc = closeMainlock;
if (rc)
{
printf("code.\n");
}
rc = waitMainlock;
if (rc)
{
printf("code.\n");
}
}
printf("Producer %x: Lock Acquired\n", (int)threadid);
sharedData++;
dataleft--;
rc = closeMainlock;
rc = signalMainlock;
if (rc)
{
printf("code.\n");
}
printf("Producer %x: Releasing Lock\n", (int)threadid);
}
}
Check out this piece of code:
if (!rc)
{
printf("Consumer %x: Completed. Exiting...\n");
exit(0);
}
If the consumer has finished, the process(!) is terminated. You need to use pthread_exit() instead, or simply return from the thread function.
Then, there is also
../nptl/pthread_mutex_lock.c:80:
__pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
which I got a few times running the code. That could be caused by e.g. double unlock or some other invalid use. I'd start with cleaning up the weird macros, so that you have a free view on the logic of the program itself.
Also, one important advise concerning mutexes: Always document precisely which data should be protected by the mutex. The point is that it's not always clear and getting this wrong means that you accidentally access data without synchronization. In order to make this very clear, use a structure like here:
struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int data;
} synced_data = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_COND_INITIALIZER,
0
};
Actually, it's not just about the shared data that documentation is important. Consider for example IsthereDataleft: This is a mutex but it doesn't guard anything, right? Instead, it is used to signal to the started threads that there is nothing left to do, right? Documenting this not only helps others to understand your code but it makes sure that you understand yourself what the intention is. Sometimes, while trying to explain it, you will then find yourself that something doesn't make sense.
Something seems to be awry with your use of openMainlock, which expands to a pthread_mutex_lock call.
One one hand, you shouldn't expect to ever get a non-zero return value from openMainlock: pthread_mutex_lock should either return zero (lock acquired) or block, unless the mutex is not initialised or is an error-checking mutex.
Further, once the lock is acquired, if the producer is done, i.e. dataleft is zero, the thread calls exit(0), which will terminate the whole process rather than terminating the thread. pthread_exit should be used instead, or just return from the function, but note that at this point you still own the main lock, which won't be released.

Creating a new thread each time a method is called using pthread

I want to create a program that creates a new thread each time a specific method is called. Here is my working code so far:
#define NUMBER_OF_THREADS 3
pthread_t threads[NUMBER_OF_THREADS];
pthread_attr_t attr;
void *BusyWork(void *t)
{
int i;
long tid;
tid = (long)t;
printf("Thread %ld running...\n",tid);
// ...
printf("Thread %ld completed...\n",tid);
pthread_exit((void*) t);
}
void createNewThread(int number){
printf("running createNewThread(%d)\n", number);
pthread_t tid;
int rc = pthread_create( &tid, &attr, BusyWork, (void *) (long)number);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
int main(int argc, char *argv[]) {
int i, rc;
//Set up thread attributes
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
//Arbitary amount of calls (My real program will call the createNewThread() funcion multiple unkown amount of times)
createNewThread(15);
createNewThread(27);
createNewThread(62);
createNewThread(500);
createNewThread(8864);
createNewThread(99999);
//Free attributes
pthread_attr_destroy(&attr);
//Wait for other threads still running
// HOW CAN I DO THIS????
/*for (i=0; i< NUMBER_OF_THREADS; i++){
rc = pthread_join( ??? , NULL); //TODO
if (rc){
printf("ERROR: return code from pthread_join() %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %d\n", i);
}*/
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL); // (?) Is this part nessassary as we are on the main thread and soon to exit the program
return 0;
}
However as you can see in my code there is a few issues! For example, how can I wait for all processes to complete for the code I am using, as I am not keeping track of the thread number. Also when a thread "BusyWork" is done it does not clean up after it self and left as an orphan process.
One idea I had was to use a vector to keep track of each thread number and then use that for the final join at the end of main. However the problem with that is the array list can easily get very large and will never shrink even though a thread is complete.
Detach the threads, don't join them. Before you create a thread, increment a counter protected by a mutex. Right before a thread terminates, acquire the mutex and decrement the counter. Now you know all threads are done when the counter reads zero. You can use a condition variable to make the counter waitable if you like.

How to use this for killing array of threads?

This code worked fine , but how to use it to kill for array of remaining threads?
#include<stdio.h>
#include<signal.h>
#include<pthread.h>
void *print1(void *tid)
{
pthread_t *td= tid;
pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock1);
printf("1");
printf("2");
printf("3");
printf("4\n");
printf("Coming out of thread1 \n");
sleep(2);
pthread_mutex_unlock(&lock1);
pthread_kill(*td,SIGKILL);//killing remaining all threads
return NULL;
}
void *print2(void *arg)
{
pthread_mutex_t *lock = arg;
pthread_mutex_lock(lock);
sleep(5);
printf("5");
sleep(5);
printf("6");
sleep(5);
printf("7");
sleep(5);
printf("8\n");
fflush(stdout);
pthread_mutex_unlock(lock);
return NULL;
}
int main()
{
int s;
pthread_t tid1, tid2;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
printf("creating Thread 1and 2 \n");
sleep(2);
pthread_create(&tid1, NULL, print1,&tid2);
pthread_create(&tid2, NULL, print2,&lock);
printf("Running Thread 1\n");
sleep(2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
Comments: Please delete this and add some extra information about the code. The editor is not allowing me to edit the code.
here is an edited version of the code
along with some commentary
#include<signal.h>
#include<pthread.h>
void *print1(void *tid)
{
// should be in global space, so no need to pass
pthread_t *td= tid;
// this is a whole new mutex,
//should be in global space so other threads can access it
pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER;
// why bother with the mutex, it does nothing useful
pthread_mutex_lock(&lock1);
printf("1");
printf("2");
printf("3");
printf("4\n");
printf("Coming out of thread1 \n");
sleep(2);
pthread_mutex_unlock(&lock1);
pthread_kill(*td,SIGKILL);//killing remaining all threads return NULL;
// this exit is not correct, it should be this call:
// void pthread_exit(void *rval_ptr);
} // end function: print1
void *print2(void *arg)
{
// this should be in global memory so all threads using same mutex
pthread_mutex_t *lock = arg;
pthread_mutex_lock(lock);
sleep(5);
printf("5");
sleep(5);
printf("6");
sleep(5);
printf("7");
sleep(5);
printf("8\n");
fflush(stdout);
pthread_mutex_unlock(lock);
// this exit is not correct, it should be this call:
// void pthread_exit(void *rval_ptr);
return NULL;
} // end function: print2
int main()
{
int s;
// this should be in global memory
// so no need to pass to threads
pthread_t tid1, tid2;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
printf("creating Thread 1and 2 \n");
// why bother to sleep here?
sleep(2);
// in these calls, the last parm should be NULL
// and the related data should be in global memory
pthread_create(&tid1, NULL, print1,&tid2);
pthread_create(&tid2, NULL, print2,&lock);
// we are still in main, so this printf is misleading
printf("Running Thread 1\n");
// no need to sleep()
// as the pthread_join calls will wait for the related thread to exit
sleep(2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
} // end function: main
However you want. There is no "one right way" to do this.
Probably the easiest way is to replace your calls to sleep with calls to a function that uses pthread_cond_timedwait and a predicate that causes the thread to call pthread_exit.
In psuedo-code, replace calls to sleep with this logic:
Compute the time to sleep until.
Lock the mutex.
Check if the predicate is set to exit, if so, call pthread_exit.
Call pthread_cond_timedwait.
Check if the predicate is set to exit, if so, call pthread_exit.
Check if the time expired, if not, go to stop 4.
And to terminate the threads, do this:
Lock the mutex.
Set the predicate to exit.
Call pthread_cond_broadcast.
Release the mutex.
Call pthread_join on the threads to wait until they've terminated.

Why does pthread_cond_signal not work?

I am currently learing all around POSIX threads (pthread).
I now have created a simple program which increased a shared value by 7 until above 10000 then it should signal a condition to the next thread which decreases it by 3 until under 1000. At last it should divide the result through 2 and main should output the result.
My code:
pthread_t threads[3];
pthread_cond_t cond_a, cond_b;
pthread_mutex_t mutex;
int counter;
void * worker_one();
void * worker_two();
void * worker_three();
int main(int argv, const char ** argc) {
counter = 0;
pthread_cond_init(&cond_a, NULL);
pthread_cond_init(&cond_b, NULL);
pthread_mutex_init(&mutex, NULL);
pthread_create(&threads[0], NULL, worker_one, NULL);
pthread_create(&threads[1], NULL, worker_two, NULL);
pthread_create(&threads[2], NULL, worker_three, NULL);
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
pthread_join(threads[2], NULL);
printf("Value started at %d and ends with %d.\n", 0, counter);
return 0;
}
void * worker_one() {
printf("Worker one started.\n");
pthread_mutex_lock(&mutex);
printf("Worker one starting work.\n");
while (counter < 10000) {
counter += 7;
}
pthread_cond_signal(&cond_a);
printf("Worker one finished work with: %d.\n", counter);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void * worker_two() {
printf("Worker two started.\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_a, &mutex);
printf("Worker two starting work.\n");
while (counter > 1000)
counter -= 3;
printf("Worker two finished work with: %d.\n", counter);
pthread_cond_signal(&cond_b);
pthread_mutex_unlock(&mutex);
sleep(1);
pthread_exit(NULL);
}
void * worker_three() {
printf("Worker three started.\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond_b, &mutex);
printf("Worker three starting work.\n");
counter /= 2;
printf("Worker three finished work with: %d.\n", counter);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
For some reason the whole execution hangs around the first thread. The signal is also fired but thread two does not react.
Can somebody tell me what I am doing wrong?
I have answered a similar question here: pthread condition variables on Linux, odd behaviour.
The problem is that you wait before even testing the condition you want to wait for is true.
What happens is that thread 1 signals before thread 2 is waiting, therefore the signal is lost and thread 2 will be waiting forever.
In order to avoid this, first test what you want to wait for, then wait only if it's not here.
EDIT: Ok, here is a possible solution with only one mutex and one condtion (untested)
Thread 1:
pthread_mutex_lock(&mutex);
while(thread_1_should_work == false){ // wait until the condition is satisfied
pthread_cond_wait(&cond, &mutex);
}
//at this point, we owe the mutex and we know thread_1_should_work is true;
// do work
thread_1_shoudl_work = false;
thread_2_should_work = true;
pthread_cond_broadcast(&cond); //wake up any waiting thread (if it's not their turn, they'll call wait again)
pthread_mutex_unlock(&mutex);
... and so on.

Resources