[LUAU] pthreads signaling question

Jim Thompson jim at netgate.com
Thu Mar 10 19:44:35 PST 2005


On Mar 10, 2005, at 4:01 PM, Charles Lockhart wrote:

> I just upgraded a RH9 box to FC1.  I then rebuilt a multi-threaded 
> program and tried to run it, but found some behaviors that don't make 
> sense to me.  One of the threads sleeps on a conditional wait ( 
> pthread_cond_wait(&my_cond, &my_mutex)), and when a different thread 
> calls pthread_cond_broadcast(&my_cond), I kind of expect the first 
> thread to wake it's shiny smiling face and do some work.  But it 
> doesn't.  Shouldn't it?  It used to.
>
> I have found some references to bugs in RH9 of people  running into 
> "stalls" with similar stuff, but that never happened to me on RH9, so 
> I figured it ought to work on FC1 as well.
>
> Any info?  Can anyone confirm or deny that I'm doing something goofy?  
> I didn't really change anything, so if there's some other library I'm 
> supposed to link to or something, please lemme know.  Or for anything 
> else too.
>
> Thanks in advance,
>
> -Charles

pthread_cond_broadcast() will (attempt) to waken *ALL* threads waiting 
on that condition variable.   If there is more than one, they'll
race, and the first one that gets past the mutex 'wins'.   
pthread_cond_signal() will attempt to waken *one* thread (typically the 
first
thread waiting on the condition variable.)

Perhaps you're just running into side-effects of the scheduler.  It 
seems to work here (gentoo, 2.6.10 kernel).  See the code and output 
below.
(I'm not bragging on the code, it was quick-n-dirty.)

The Fedora Project officially ended support for Fedora Core 1 (FC1) on 
September 20th, 2004.  FC3 was released November 8, 2004.
Maybe you should run FC3 (which is current) .vs a release that is now 
known as "Fedora Legacy".  (http://fedora.redhat.com/)

jim

/home/jim> cat thread_signal.c
#include <pthread.h>
#include <stdio.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int workToDo = 0;

#define NTHREADS 5

void *
func(void *parm)
{
     int rc;
     int id = (int) parm;

     while (1) {
         /* Usually worker threads will loop on these operations */
         if ((rc = pthread_mutex_lock(&mutex)) < 0) {
           fprintf(stderr, "thread %d, pthread_mutex_lock(): %s\n",
               id, strerror(rc)); /* strerror not thread-safe */
           pthread_exit(NULL);
         }

         while (!workToDo) {
             printf("\tThread %d blocked\n", id);
             if ((rc = pthread_cond_wait(&cond, &mutex)) < 0) {
               fprintf(stderr, "thread %d, pthread_cond_wait(): %s\n",
                   id, strerror(rc)); /* not thread-safe */
               pthread_exit(NULL);
             }
         }
          printf("\tThread %d awake, finish work!\n", id);

          /* Under protection of the lock, complete or remove the work   
   */
          /* from whatever worker queue we have. Here it is simply a 
flag  */
          workToDo = 0;

         if ((rc = pthread_mutex_unlock(&mutex)) < 0) {
           fprintf(stderr, "thread %d, pthread_mutex_unlock(): %s\n",
               id, strerror(rc)); /* strerror not thread-safe */
           pthread_exit(NULL);
         }
   }
   return NULL;
}

int
main(int argc, char **argv)
{
   pthread_t threadid[NTHREADS];
   int rc, i;

   printf("Create %d threads\n", NTHREADS);
   for (i = 0; i < NTHREADS; i++) {
       if ((rc = pthread_create(&threadid[i], NULL, func, (void *)i)) < 
0) {
         perror("pthread_create");
         exit(1);
       }
    }

   sleep(1);  /* Sleep is not a robust way to serialize threads */

   for (i = 0; i < 5; ++i) {
       printf("Wake up a worker, work to do...\n");

       if ((rc = pthread_mutex_lock(&mutex)) < 0) {
           perror("pthread_mutex_lock()");
           exit(1);
       }

       /* 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;

#ifdef COND_SIGNAL
       if ((rc = pthread_cond_signal(&cond)) < 0) {
           perror("pthread_cond_signal()");
           exit(1);
       }
#else
       if ((rc = pthread_cond_broadcast(&cond)) < 0) {
           perror("pthread_cond_signal()");
           exit(1);
       }
#endif

       if ((rc = pthread_mutex_unlock(&mutex)) < 0) {
           perror("pthread_mutex_unlock()");
           exit(1);
       }

       sleep(1); /* Sleep is not a robust way to serialize threads */
   }

   exit(0);
}

/home/jim> gcc thread_signal.c -o thread_signal -lpthread
/home/jim> gcc -DCOND_SIGNAL=1 thread_signal.c -o thread_cond_signal 
-lpthread
/home/jim> gcc thread_signal.c -o thread_cond_broadcast -lpthread
/home/jim> ./thread_cond_signal
Create 5 threads
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
Wake up a worker, work to do...
         Thread 1 awake, finish work!
         Thread 1 blocked
Wake up a worker, work to do...
         Thread 2 awake, finish work!
         Thread 2 blocked
Wake up a worker, work to do...
         Thread 3 awake, finish work!
         Thread 3 blocked
Wake up a worker, work to do...
         Thread 4 awake, finish work!
         Thread 4 blocked
/home/jim> ./thread_cond_broadcast
Create 5 threads
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
Wake up a worker, work to do...
         Thread 0 awake, finish work!
         Thread 0 blocked
         Thread 1 blocked
         Thread 2 blocked
         Thread 3 blocked
         Thread 4 blocked
/home/jim>




More information about the LUAU mailing list