I don't know what to say. You are obviously right and I am obviously wrong. Justification soon. If I offended anyone I apologize; it was not my intention. Up until this post I made the mistake that Codeplug suggested; namely spurious wakeups as two or more threads running the loop the same time. Thank you for reading my example and observing my mistake. ![Smile](https://cboard.cprogramming.com/images/smilies/smile.png)
Now, let me give you some source code for the next guy who will show up with the same idea I had.
The program creates N threads, one of them (signaling) sleeps for 1 second until the rest are initialized for sure (I create it last one as well). The other ones, acquire the mutex, and wait for a signal by the "signaling" one. After a second, the signaling thread sends the signal, and ONLY one of the other threads prints a message, exactly as all of you have suggested. However, even after releasing the mutex once again, no other thread wakes up in my machine, no matter how many threads I created (I've tested several values up to even 2000).
But now I have another question. ![Smile](https://cboard.cprogramming.com/images/smilies/smile.png)
How can we have an example (even based on chance) where at least two threads wake up by a single signal?
And another thing: Is there a good known mechanism for countering a problem of a "shared data structure" just like I wanted, or the approach with the while loop is simple and fine after all?
May be I have some other questions as well, but I have to think a little bit more. ![Smile](https://cboard.cprogramming.com/images/smilies/smile.png)
Thank you all for replying. Oh, and by the way, I really meant that I want someone to paraphrase this:
The thread(s) that are unblocked shall contend for the mutex according to the scheduling policy (if applicable), and as if each had called pthread_mutex_lock().
Now the program that I promised above.
The output with just three threads:
Code:
$ gcc lol.c -pthread -o lol
$ ./lol
1: I own the mutex. I will increment those waiting for a condition.
I will release the mutex now and call pthread_cond_wait ().
2: I own the mutex. I will increment those waiting for a condition.
I will release the mutex now and call pthread_cond_wait ().
3: I own the mutex and I am about to signal.
2 threads waiting for a condition.
-----------------------------------------------------------------------
Signal sent. Now releasing mutex.
-----------------------------------------------------------------------
1: 1 thread is waiting.
I will release the mutex to check how many woke up.
1: mutex released.
^C
$
And the source code:
Code:
/*
** How many threads wake up?
*/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct {
int id;
int * waiting;
pthread_mutex_t * mutex;
pthread_cond_t * condition;
} DATA;
#define NUM_THREADS 3
#define SLEEPING_THREADS (NUM_THREADS - 1)
void * signaling_function (void *);
void * waiting_function (void *);
int main (void)
{
int i, rc;
void * status;
DATA data_struct [NUM_THREADS];
pthread_t threads [NUM_THREADS];
pthread_attr_t attr;
pthread_mutex_t m;
pthread_cond_t cond;
int those_waiting;
/* Initializations. */
/* Make threads Joinable for sure. */
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);
/* mutex and condition variable. */
pthread_mutex_init (&m, NULL);
pthread_cond_init (&cond, NULL);
those_waiting = 0; /* nobody is waiting for something at the beginning. */
/* Pass the ids to the threads. */
for (i = 0; i < NUM_THREADS; i++) {
data_struct [i].waiting = &those_waiting;
data_struct [i].id = i + 1;
data_struct [i].mutex = &m;
data_struct [i].condition = &cond;
}
/* Create threads. */
for (i = 0; i < SLEEPING_THREADS; i++) {
rc = pthread_create(&(threads[i]), &attr, waiting_function, (void *) &(data_struct [i]));
if (rc) {
printf ("ERROR; return code from pthread_create() is %d.\n", rc);
exit (2);
}
}
/* Create the signaling function last. */
rc = pthread_create(&(threads[NUM_THREADS - 1]), &attr,
signaling_function, (void *) &(data_struct [NUM_THREADS - 1]));
if (rc) {
printf ("ERROR; return code from pthread_create() is %d.\n", rc);
exit (1);
}
/* Wait for threads to join. */
for (i = 0; i < NUM_THREADS; i++)
pthread_join ( threads [i], &status );
printf ("Threads joined!\n");
pthread_exit (NULL);
}
void * signaling_function (void * input)
{
DATA * myData = (DATA *) input;
sleep (1); /* Enough time so that others can "hibernate" ... */
pthread_mutex_lock (myData->mutex);
printf ("\n%5d: I own the mutex and I am about to signal.\n", myData->id);
printf (" %d threads waiting for a condition.\n", *(myData->waiting));
printf ("\n-----------------------------------------------------------------------\n\n");
pthread_cond_signal (myData->condition);
sleep (1);
printf (" Signal sent. Now releasing mutex.\n");
printf ("\n-----------------------------------------------------------------------\n\n");
pthread_mutex_unlock (myData->mutex);
pthread_exit (NULL);
}
void * waiting_function (void * input)
{
DATA * myData = (DATA *) input;
pthread_mutex_lock (myData->mutex);
printf ("%5d: I own the mutex. I will increment those waiting for a condition.\n", myData->id);
(*(myData->waiting))++;
printf (" I will release the mutex now and call pthread_cond_wait ().\n");
pthread_cond_wait (myData->condition, myData->mutex);
(*(myData->waiting))--;
sleep(1);
if (*(myData->waiting) != 1)
printf ("%5d: %d threads are waiting.\n", myData->id, *(myData->waiting));
else
printf ("%5d: %d thread is waiting.\n", myData->id, *(myData->waiting));
/* You can comment the following 3 lines ... */
printf (" I will release the mutex to check how many woke up.\n");
pthread_mutex_unlock (myData->mutex);
printf ("%5d: mutex released.\n\n", myData->id);
pthread_exit (NULL);
}