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.
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.
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.
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);
}