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>

Reply via email to