pthread_cond_broadcast on SMP systems

Bill Spitzak <[email protected]> Fri, 3 Oct 2003 18:11:23 -0700
Newsgroups gmane.linux.ngpt.devel
Message-ID <[email protected]>
Hi! I am developing software at Digital Domain (partially owned by IBM) and 
am having some trouble with RedHat 9 on an SMP system and am trying to find 
out if there is a bug in pthreads or if I am just using it wrong.

It seems to me that pthread_cond_broadcast does not actually wake up all 
threads waiting on the signal, if one of them also did a 
pthread_cond_broadcast with the same condition. On older Linux systems and 
also on Irix and Windows pthreads emulation I don't seem to have this problem.

The attached program takes one argument, N, which is how many threads to 
make. You should also redirect the input from some file. On most systems it 
will run until eof, but on RedHat 9 when SMP is enabled (on a 2-processor 
machine with Hyperthreading) and threads is set to 3 or more it will hang 
rather quickly, with all the threads in wait state.

Recompiling it with -DFIXED will make a working program, where a different 
condition is used by the other threads to signal back to the main thread. 
This would indicate that setting the same conditions by the receiving thread 
is the problem. In my actual code this is quite difficult to work around as 
each thread is identical and all are working on parts of the same problem, 
though I was able to change all my broadcast/wait calls to new ones that 
allocate a temporary condition so only one is used at a time.

Can anybody confirm if this is a bug, or that I am using pthreads wrong?

Please respond directly to spitzak at d2 dot com as I am not subscribed to 
the list.

=== cut here ===
#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex;
pthread_mutexattr_t attrib = {PTHREAD_MUTEX_RECURSIVE_NP};
pthread_cond_t cond;

#ifdef FIXED
pthread_cond_t cond2;
#define COND2 cond2
#else
#define COND2 cond
#endif

int n = 0;
int m = 0;

void* thread_proc(void* v) {
  int i = (int)v;
  int pn = 0;
  pthread_mutex_lock(&mutex);
  for (;;) {
    while (n == pn) pthread_cond_wait(&cond, &mutex);
    pn = n;
    m++;
    pthread_cond_broadcast(&COND2);
    printf("%*d %d\n", 10*i, i, n);
  }
}

pthread_attr_t attr;
pthread_t threads[100];

int main(int argc, char** argv) {
  int pm = 0;
  int numthreads = atoi(argv[1]);
  int i;

  pthread_mutex_init(&mutex, &attrib);
  pthread_cond_init(&cond, 0);
#ifdef FIXED
  pthread_cond_init(&cond2, 0);
#endif

  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  for (i = 1; i < numthreads; i++)
    pthread_create(&threads[i], &attr, thread_proc, (void*)(i));

  while (getchar() >= 0) {
    pthread_mutex_lock(&mutex);
    n = n+1;
    printf("%d\n", n);
    pthread_cond_broadcast(&cond);
    m++;
    while (m < pm+numthreads) pthread_cond_wait(&COND2, &mutex);
    pm = m;
    pthread_mutex_unlock(&mutex);
  }
}
=== cut here ===

-- 
                   ,~,~,~,~ ~ ~ ~ ~
     /\_       _|_========___         Bill Spitzak
 ~~~/\/\\~~~~~~\____________/~~~~~~~~ [email protected]