#include <stdio.h>
#include <pthread.h>
#define MAX 10 /* maximum iterations */
int number; /* the resource */
pthread_mutex_t mu= PTHREAD_MUTEX_INITIALIZER; /* to protect the resource*/
/*
Condition variable to signal consumer that a new number is available for
consumption.
*/
pthread_cond_t sig_consumer= PTHREAD_COND_INITIALIZER;
/*
Condition variable to signal the producer that
(a) the new number has been consumed,
(b) generate another one.
*/
pthread_cond_t sig_producer= PTHREAD_COND_INITIALIZER;
void *consumer(void *dummy)
{
int printed= 0;
printf("Consumer : \"Hello I am consumer #%ld. Ready to consume numbers"
" now\"\n", pthread_self());
while (1)
{
pthread_mutex_lock(&mu);
/* Signal the producer that the consumer is ready. */
pthread_cond_signal(&sig_producer);
/* Wait for a new number. */
pthread_cond_wait(&sig_consumer, &mu);
/* Consume (print) the number. */
printf("Consumer : %d\n", number);
/* Unlock the mutex. */
pthread_mutex_unlock(&mu);
/*
If the MAX number was the last consumed number, the consumer should
stop.
*/
if (number == MAX)
{
printf("Consumer done.. !!\n");
break;
}
}
}
/**
#func producer
This function is responsible for incrementing the number and signalling the
consumer.
*/
void *producer(void *dummy)
{
printf("Producer : \"Hello I am producer #%ld. Ready to produce numbers"
" now\"\n", pthread_self());
while (1)
{
pthread_mutex_lock(&mu);
number ++;
printf("Producer : %d\n", number);
/*
Signal the consumer that a new number has been generated for its
consumption.
*/
pthread_cond_signal(&sig_consumer);
/*
Now wait for consumer to confirm. Note, expect no confirmation for
consumption of MAX from consumer.
*/
if (number != MAX)
pthread_cond_wait(&sig_producer, &mu);
/* Unlock the mutex. */
pthread_mutex_unlock(&mu);
/* Stop if MAX has been produced. */
if (number == MAX)
{
printf("Producer done.. !!\n");
break;
}
}
}
void main()
{
int rc, i;
pthread_t t[2];
number= 0;
/* Create consumer & producer threads. */
if ((rc= pthread_create(&t[0], NULL, consumer, NULL)))
printf("Error creating the consumer thread..\n");
if ((rc= pthread_create(&t[1], NULL, producer, NULL)))
printf("Error creating the producer thread..\n");
/* Wait for consumer/producer to exit. */
for (i= 0; i < 2; i ++)
pthread_join(t[i], NULL);
printf("Done..\n");
}
Question: If the consumer thread is started before the producer thread, then the program will provide the expected result, but if the producer is started first, then the consumer will start consuming from number 2 onwards; the consumer is unable consume number 1. How to correct the program even though the producer thread starts first, without introducing any additional variable or sleep?
The problem with pthread_cond_t is its name. Despite being nominally a "condition", it has no state... in particular, it does not remember that it has been signalled at all -- if you thought it might count how many times it has been signalled, you will be disappointed (for that you need a semaphore). To put that another way, if there is no pthread waiting on a condition when it is signalled, the signal has no effect and is forgotten.
The "condition" is better thought of as a "wait queue", where pthreads wait for some state to be updated. So usually you have some state, protected by the mutex. If the state is not as required for the pthread to continue, then the pthread waits on the "condition". When the state is updated, the "condition" can be signalled. When the waiter wakes up, it must check the state, and decide whether everything is now ready to continue.
Where there are two or more pthreads waiting, the standard allows pthread_cond_signal() to wake up one, two or more, or all, the waiters. The mutex ensures that the waiters' access to the state is serialised, but the waiter cannot (in general, and for this reason in particular) assume that the state is unchanged since the signal. So, it is common to write the waiter:
pthread_mutex_lock(&mutex) ;
....
while(...what we need to continue...)
pthread_cond_wait(&cond, &mutex) ;
....
pthread_mutex_unlock(&mutex) ;
Which reflects the importance of the state, and how little the "condition" contributes.
Related
So I'm trying to understand exactly how pthread_mutex_lock works.
My current understanding is that it unlocks the mutex and puts whatever thread is going though it to sleep. Sleep meaning that the thread is inactive and consuming no resources.
It then waits for a signal to go from asleep to blocked, meaning that the thread can no longer change any variables.
thread 1:
pthread_mutex_lock(&mutex);
while (!condition){
printf("Thread wating.\n");
pthread_cond_wait(&cond, &mutex);
printf("Thread awakened.\n");
fflush(stdout);
}
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condVar);
pthread_mutex_unlock(&mutex);
So basically in the sample above, the loop runs and runs and each iteration pthread_cond_wait checks if the condition of the loop is true. If it is then the cond_signal is sent and the thread is blocked so it can't manipulate any more data.
I'm really having trouble wrapping my head around this, I'd appreciate some input and feedback about how this works and whether or not I am beginning to understand this based on what I have above.
I've gone over this post but am still having trouble
First, a summary:
pthread_mutex_lock(&mutex):
If mutex is free, then this thread grabs it immediately.
If mutex is grabbed, then this thread waits until the mutex becomes free, and then grabs it.
pthread_mutex_trylock(&mutex):
If mutex is free, then this thread grabs it.
If mutex is grabbed, then the call returns immediately with EBUSY.
pthread_mutex_unlock(&mutex):
Releases mutex.
pthread_cond_signal(&cond):
Wake up one thread waiting on the condition variable cond.
pthread_cond_broadcast(&cond):
Wake up all threads waiting on the condition variable cond.
pthread_cond_wait(&cond, &mutex):
This must be called with mutex grabbed.
The calling thread will temporarily release mutex and wait on cond.
When cond is broadcast on, or signaled on and this thread happens to be the one woken up, then the calling thread will first re-grab the mutex, and then return from the call.
It is important to note that at all times, the calling thread either has mutex grabbed, or is waiting on cond. There is no interval in between.
Let's look at a practical, running example code. We'll create it along the lines of OP's code.
First, we'll use a structure to hold the parameters for each worker function. Since we'll want the mutex and the condition variable to be shared between threads, we'll use pointers.
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <pthread.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/* Worker function work. */
struct work {
pthread_t thread_id;
pthread_mutex_t *lock; /* Pointer to the mutex to use */
pthread_cond_t *wait; /* Pointer to the condition variable to use */
volatile int *done; /* Pointer to the flag to check */
FILE *out; /* Stream to output to */
long id; /* Identity of this thread */
unsigned long count; /* Number of times this thread iterated. */
};
The thread worker function receives a pointer to the above structure. Each thread iterates the loop once, then waits on the condition variable. When woken up, if the done flag is still zero, the thread iterates the loop. Otherwise, the thread exits.
/* Example worker function. */
void *worker(void *workptr)
{
struct work *const work = workptr;
pthread_mutex_lock(work->lock);
/* Loop as long as *done == 0: */
while (!*(work->done)) {
/* *(work->lock) is ours at this point. */
/* This is a new iteration. */
work->count++;
/* Do the work. */
fprintf(work->out, "Thread %ld iteration %lu\n", work->id, work->count);
fflush(work->out);
/* Wait for wakeup. */
pthread_cond_wait(work->wait, work->lock);
}
/* *(work->lock) is still ours, but we've been told that all work is done already. */
/* Release the mutex and be done. */
pthread_mutex_unlock(work->lock);
return NULL;
}
To run the above, we'll need a main() as well:
#ifndef THREADS
#define THREADS 4
#endif
int main(void)
{
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t wait = PTHREAD_COND_INITIALIZER;
volatile int done = 0;
struct work w[THREADS];
char *line = NULL, *p;
size_t size = 0;
ssize_t len = 0;
unsigned long total;
pthread_attr_t attrs;
int i, err;
/* The worker functions require very little stack, but the default stack
size is huge. Limit that, to reduce the (virtual) memory use. */
pthread_attr_init(&attrs);
pthread_attr_setstacksize(&attrs, 2 * PTHREAD_STACK_MIN);
/* Grab the mutex so the threads will have to wait to grab it. */
pthread_mutex_lock(&lock);
/* Create THREADS worker threads. */
for (i = 0; i < THREADS; i++) {
/* All threads use the same mutex, condition variable, and done flag. */
w[i].lock = &lock;
w[i].wait = &wait;
w[i].done = &done;
/* All threads output to standard output. */
w[i].out = stdout;
/* The rest of the fields are thread-specific. */
w[i].id = i + 1;
w[i].count = 0;
err = pthread_create(&(w[i].thread_id), &attrs, worker, (void *)&(w[i]));
if (err) {
fprintf(stderr, "Cannot create thread %d of %d: %s.\n", i+1, THREADS, strerror(errno));
exit(EXIT_FAILURE); /* Exits the entire process, killing any other threads as well. */
}
}
fprintf(stderr, "The first character on each line controls the type of event:\n");
fprintf(stderr, " e, q exit\n");
fprintf(stderr, " s signal\n");
fprintf(stderr, " b broadcast\n");
fflush(stderr);
/* Let each thread grab the mutex now. */
pthread_mutex_unlock(&lock);
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Find the first character on the line, ignoring leading whitespace. */
p = line;
while ((p < line + len) && (*p == '\0' || *p == '\t' || *p == '\n' ||
*p == '\v' || *p == '\f' || *p == '\r' || *p == ' '))
p++;
/* Do the operation mentioned */
if (*p == 'e' || *p == 'E' || *p == 'q' || *p == 'Q')
break;
else
if (*p == 's' || *p == 'S')
pthread_cond_signal(&wait);
else
if (*p == 'b' || *p == 'B')
pthread_cond_broadcast(&wait);
}
/* It is time for the worker threads to be done. */
pthread_mutex_lock(&lock);
done = 1;
pthread_mutex_unlock(&lock);
/* To ensure all threads see the state of that flag,
we wake up all threads by broadcasting on the condition variable. */
pthread_cond_broadcast(&wait);
/* Reap all threds. */
for (i = 0; i < THREADS; i++)
pthread_join(w[i].thread_id, NULL);
/* Output the thread statistics. */
total = 0;
for (i = 0; i < THREADS; i++) {
total += w[i].count;
fprintf(stderr, "Thread %ld: %lu events.\n", w[i].id, w[i].count);
}
fprintf(stderr, "Total: %lu events.\n", total);
return EXIT_SUCCESS;
}
If you save the above as example.c, you can compile it to example using e.g. gcc -Wall -O2 example.c -lpthread -o example.
To get the correct intuitive grasp of the operations, run the example in a terminal, with the source code in a window next to it, and see how the execution progresses as you provide input.
You can even run commands like printf '%s\n' s s s b q | ./example to run a sequence of events in a quick succession, or printf 's\ns\ns\nb\nq\n' | ./example with even less time in between events.
After some experimentation, you'll hopefully find out that not all input events cause their respective action. This is because the exit event (q above) is not synchronous: it does not wait for all pending work to be done, but tells the threads to exit right then and there. That is why the number of events may vary even for the exact same input.
(Also, if you signal on the condition variable, and immediately broadcast on it, the threads tend to only get woken up once.)
You can mitigate that by delaying the exit, using e.g. (printf '%s\n' s s b s s s ; sleep 1 ; printf 'q\n' ) | ./example.
However, there are better ways. A condition variable is not suitable for countable events; it is really flag-like. A semaphore would work better, but then you should be careful to not overflow the semaphore; it can only be from 0 to SEM_VALUE_MAX, inclusive. (So, you could use a semaphore to represent the number of pending job, but probably not for the number of iterations done by each/all thread workers.) A queue for the work to do, in thread pool fashion, is the most common approach.
pthread_cond_wait() simply means that the current thread shall release the mutex and then waits on a condition. The trick here is that both happens atomically, so it cannot happen, that the thread has released the mutex and is not yet waiting on the condition or is already waiting on the condition and has not yet released the mutex. Either both has happened or none has happened.
pthread_cond_signal() simply wakes up any thread that is currently waiting on the signaled condition. The first thing the woken up thread will do is obtaining the mutex again, if it cannot obtain it (e.g. as the signaling thread is currently owning the mutex), it will block until it can. If multiple threads are waiting on the condition, pthread_cond_signal() just wakes up one of them, which one is not defined. If you want to wake up all the waiting threads, you must use pthread_cond_broadcast() instead; but of course they won't run at the same time as now each of them first requires to obtain the mutex and that will only be possible one after another.
pthread_cond_t has no state. If you signal a condition no thread is waiting for, then nothing will happen. It's not like this will set a flag internally and if later on some thread calls pthread_cond_wait(), it will be woken up immediately as there is a pending signal. pthread_cond_signal() only wakes up threads that are already waiting, that means these threads must have called pthread_cond_wait() prior to you calling pthread_cond_signal().
Here's some simple sample code. First a reader thread:
// === Thread 1 ===
// We want to process an item from a list.
// To make sure the list is not altered by one
// thread while another thread is accessing it,
// it is protected by a mutex.
pthread_mutex_lock(&listLock);
// Now nobody but us is allowed to access the list.
// But what if the list is empty?
while (list->count == 0) {
// As long as we hold the mutex, no other thread
// thread can add anything to the list. So we
// must release it. But we want to know as soon
// as another thread has changed it.
pthread_cond_wait(&listCondition, &listLock);
// When we get here, somebody has signaled the
// condition and we have the mutex again and
// thus are allowed to access the list. The list
// may however still be empty, as another thread
// may have already consumed the new item in case
// there are multiple readers and all are woken
// up, thus the while-loop. If the list is still
// empty, we just go back to sleep and wait again.
}
// If we get here, the list is not empty.
processListItem(list);
// Finally we release the mutex again.
pthread_mutex_unlock(&listLock);
And then a writer thread:
// === Thread 2 ===
// We want to add a new item to the list.
// To make sure that nobody is accessing the
// list while we do, we need to obtain the mutex.
pthread_mutex_lock(&listLock);
// Now nobody but us is allowed to access the list.
// Check if the list is empty.
bool listWasEmpty = (list->count == 0);
// We add our item.
addListItem(list, newItem);
// If the list was empty, one or even multiple
// threads may be waiting for us adding an item.
// So we should wake them up here.
if (listWasEmpty) {
// If any thread is waiting for that condition,
// wake it up as now there is an item to process.
pthread_cond_signal(&listCondition);
}
// Finally we must release the mutex again.
pthread_mutex_unlock(&listLock);
The code is written so that there can be any number of reader/writer threads. Signaling only if the list was empty (listWasEmpty) is just a performance optimization, the code would also work correctly if you always signal the condition after adding an item.
In the code below:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mtx;
pthread_cond_t cond;
int how_many = 10;
int pool = 0;
void * producer(void * ptr)
{
while (how_many > 0)
{
pthread_mutex_lock(&mtx);
printf("producer: %d\n", how_many);
pool = how_many;
how_many--;
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cond);
}
pthread_exit(0);
}
void * consumer(void * ptr)
{
while (how_many > 0)
{
pthread_mutex_lock(&mtx);
pthread_cond_wait(&cond, &mtx);
printf("consumer: %d\n", pool);
pool = 0;
pthread_mutex_unlock(&mtx);
}
pthread_exit(0);
}
int main(int argc, char ** argv)
{
pthread_t prod, cons;
pthread_mutex_init(&mtx, 0);
pthread_cond_init(&cond, 0);
pthread_create(&cons, 0, consumer, 0);
pthread_create(&prod, 0, producer, 0);
pthread_join(prod, 0);
pthread_join(cons, 0);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mtx);
return 0;
}
I'm not getting the expected output.
Expected output:
Producer:10
Consumer:10
Producer:9
Consumer:9
Producer:8
Consumer:8
Producer:7
Consumer:7
Producer:6
Consumer:6
Producer:5
Consumer:5
Producer:4
Consumer:4
Producer:3
Consumer:3
Producer:2
Consumer:2
Producer:1
Consumer:1
Actual output:
producer: 10
producer: 9
producer: 8
producer: 7
producer: 6
producer: 5
producer: 4
producer: 3
producer: 2
producer: 1
Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?
Will it be dead lock?
My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. Is that true?
Mutexes provide only mutual exclusion (when used properly); they do not themselves provide a mechanism for blocking on a specific event to happen or until a specific condition is satisfied. That's what condition variables are for (and semaphores, if you want to go a little lower-level).
Your code provides for the consumer to wait on the producer to produce, but not for the producer to wait on the consumer to consume before it continues. If you want the two threads to alternate, then you need a second condition variable to provide for the latter.
Also, in consumer side, If we lock and wait for the signal, how the producer can get the lock so that he can send the signal to the consumer?
will it be dead lock?
My friends are suggesting like pthread_cond_wait(&cond, &mtx); would actually unlock the resources until it gets the signal from producer. is that true?
Rather than asking your friends -- or the Internet -- have you considered reading the documentation? Here's the way the man page describes it:
These functions atomically release mutex [...]. Upon successful return, the mutex shall have been locked and shall be owned by the calling thread.
That is, the thread calling pthread_cond_wait() does not hold the mutex locked while it is waiting, but it reacquires the mutex before it returns (which may involve an indeterminate delay between the thread receiving the signal and the function call returning).
Additionally, always remember that a thread can wake up spurriously from waiting on a condition variable. It is essential to check upon wakeup whether the condition is in fact satisfied, and to resume waiting if not.
Here's a way you could structure the producer:
void * producer(void * ptr)
{
pthread_mutex_lock(&mtx);
while (how_many > 0)
{
if (pool == 0) {
printf("producer: %d\n", how_many);
pool = how_many;
how_many--;
pthread_cond_signal(&full_cond);
}
pthread_cond_wait(&empty_cond, &mtx);
}
pthread_mutex_unlock(&mtx);
pthread_exit(0);
}
Note that:
I have renamed your original condition variable and introduced a new one. There is now full_cond, indicating that the pool (of capacity 1) is full, and empty_cond, indicating that the pool is empty.
The whole loop is protected by a mutex. This is fine because it performs a pthread_cond_wait() naming that mutex; the other threads will be able to run while the the producer is waiting. The mutex ensures that access to the how_many and pool variables is correctly synchronized.
The loop protects against spurrious wakeup by testing pool to verify that it really is empty. If not, it loops back to the wait without doing anything else.
For this to work correctly, the consumer requires corresponding changes (left as an exercise for you).
You are checking how_many out of the locked section. You need to restructure you code so that reading the variable is covered by a lock or so that it is C11 _Atomic.
Even then, your code's output is likely not going to be the way you want it as the scheduling of the threads is pretty much unpredictable.
For your expected output you can use the locking mechanism like below,
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
sem_t mutex1;
sem_t mutex2;
int main()
{
pthread_t thread1, thread2;
sem_init(&mutex1, 0, 1);
sem_init(&mutex2, 0, 0);
pthread_create( &thread1, NULL, &producer, NULL)
pthread_create( &thread2, NULL, &consumer, NULL)
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
return 0;
}
void producer()
{
sem_wait(&mutex1);
:
:
sem_post(&mutex2);
}
void consumer ()
{
sem_wait(&mutex2);
:
:
sem_post(&mutex1);
}
I got the below code from this website:
https://computing.llnl.gov/tutorials/pthreads/#Abstract
This simple example code demonstrates the use of several Pthread
condition variable routines. The main routine creates three threads.
Two of the threads perform work and update a "count" variable. The
third thread waits until the count variable reaches a specified value.
My question is- how does the below code ensure that one of the two worker threads doesn't lock on the mutex before the watcher thread locks on it? If this was to happen, the watcher thread would be locked out and pthread_cond_wait(&count_threshold_cv, &count_mutex) would never get called?
I am under the assumption pthread_create() actually begins the thread too. Is the only reason this works because the pthread_create() for the watcher thread begins before the pthread_create() for the two worker threads?! Surely this is not cast-iron and the scheduling could cause a worker thread to begin before the watcher thread? Even the compiler could potentially re-order these lines of code?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 3
#define TCOUNT 10
#define COUNT_LIMIT 12
int count = 0;
int thread_ids[3] = {0,1,2};
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;
void *inc_count(void *t)
{
int i;
long my_id = (long)t;
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);
}
pthread_exit(NULL);
}
void *watch_count(void *t)
{
long my_id = (long)t;
printf("Starting watch_count(): thread %ld\n", my_id);
/*
Lock mutex and wait for signal. Note that the pthread_cond_wait
routine will automatically and atomically unlock mutex while it waits.
Also, note that if COUNT_LIMIT is reached before this routine is run by
the waiting thread, the loop will be skipped to prevent pthread_cond_wait
from never returning.
*/
pthread_mutex_lock(&count_mutex);
while (count<COUNT_LIMIT) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("watch_count(): thread %ld Condition signal received.\n", my_id);
count += 125;
printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
int i, rc;
long t1=1, t2=2, t3=3;
pthread_t threads[3];
pthread_attr_t attr;
/* Initialize mutex and condition variable objects */
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init (&count_threshold_cv, NULL);
/* For portability, explicitly create threads in a joinable state */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0], &attr, watch_count, (void *)t1);
pthread_create(&threads[1], &attr, inc_count, (void *)t2);
pthread_create(&threads[2], &attr, inc_count, (void *)t3);
/* Wait for all threads to complete */
for (i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS);
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL);
}
My question is- how does the below code ensure that one of the two worker threads doesn't lock on the >mutex before the watcher thread locks on it?
The code doesn't need to ensure that. It doesn't depend on the watcher thread calling pthread_cond_wait().
The watcher thread checks count<COUNT_LIMIT, this is the actual condition the thread care about - or rather the inverse, when count >= COUNT_LIMIT - the watcher thread knows that the other threads are done.
The pthread condition variable used in pthread_cond_wait() is just needed in case the threads are not done, so the watcher thread can be put to sleep and woken up to check the condition it cares about.
That said, the example looks a tad silly, it's not quite clear what watcher thread wants to achieve by doing count += 125;
the comment in your code explains that you do not have to worry about that:
Also, note that if COUNT_LIMIT is reached before this routine is run by
the waiting thread, the loop will be skipped to prevent pthread_cond_wait
from never returning.
in fact, if you notice, the while loop is run only if COUNT_LIMIT is not already reached by count. If that is the case, the pthread_cond_signal is not called at all.
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.
So i'm working on this code that is a producer-consumer code. It runs completely through the program, it just never actually executes anything in the critical section because it never really wakes up from sleep! I've added print statements everywhere to try to figure out where the code is executing, and it enters both producer and consumer functions, but never enters any portion of it after the sleep() function.
Here is my main:
/* 1. Get command line arguments argv[1], argv[2], argv[3] */
/* n1=arg[2], n2=arg[3]
/* 2. Initialize buffer, mutex, semaphores, and other global vars */
/*create the mutex lock */
/* create the semaphore and initialize it to 3 */
/*creating full semaphore and initializing it to 0 */
/*** critical section ***/
/* get the default attribute */
pthread_attr_init(&attr);
/* 3. Create producer thread(s) */
while (count < n1)
{
pthread_t tid;
/* create a new thread */
pthread_create(&tid, &attr, producer, NULL);
count++;
}
printf("OUTSIDE OF PRODUCER CREATION\n");
/* 4. Create consumer thread(s) */
count = 0;
while(count < n2)
{
pthread_t tid2;
/* create a new thread */
pthread_create(&tid2, &attr, consumer, NULL);
count++;
}
printf("after the crit section \n");
/* 5. Sleep */
/* 6. Realease resources, e.g destroy mutex and semaphores */
i've included for the most part just the code that I know i'm having a problem with and the rest are comments. and here is the code for my producer. consumer is basically the same:
void *producer(void *param) {
buffer_item rand;
unsigned int *seed;
seed = (unsigned int *)malloc(sizeof(unsigned int));
*seed = 10;
while (1) {
printf("Inside producer function\n");
/* Sleep for a random period of time */
r = (rand_r(seed))/divide;
sleep(r);
printf("producer slept\n");
//wait(empty)
//wait(mutex)
printf("producer locked mutex\n");
//crit section - add item to buffer
/*Generate a random number */
/*insert random number*/
printf("producer inserted item \n");
if (resp < 0)
printf("Producer error condition\n"); //Report error condition
//signal mutex
//signal empty
}
}
so when i run a.out 4 4 4, i get this as my output:
Inside producer function
Inside producer function
Inside producer function
OUTSIDE OF PRODUCER CREATION
Inside producer function
inside consumer function
inside consumer function
inside consumer function
after the crit section
inside consumer function
I'm not sure if its normal that things look like they are running out of order... it is executing 4 times but as you can see if never hits that print statement that happens after my sleep function (for both producer and consumer)
This is homework so i'm just looking for a bit more direction on this...
From the discussion, your error was that your sleep() values were too large, one you quoted coming out to 22 minutes. Rather than division(/) to limit the values, modulo(%) will put your values within a range. I recommend %10, or some other value which will limit the sleeps to a reasonable range.