Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

can pthread_cond_signal make more than one thread to wake up?

I'm studying on condition variables of Pthread. When I'm reading the explanation of pthread_cond_signal, I see the following.

The pthread_cond_signal() function shall unblock at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).

Till now I knew pthread_cond_signal() would make only one thread to wake up at a time. But, the quoted explanation says at least one. What does it mean? Can it make more than one thread wake up? If yes, why is there pthread_cond_broadcast()?


En passant, I wish the following code taken from UNIX Systems Programming book of Robbins is also related to my question. Is there any reason the author's pthread_cond_broadcast() usage instead of pthread_cond_signal() in waitbarrier function? As a minor point, why is !berror checking needed too as a part of the predicate? When I try both of them by changing, I cannot see any difference.

/*

 The program implements a thread-safe barrier by using condition variables. The limit
 variable specifies how many threads must arrive at the barrier (execute the
 waitbarrier)  before the threads are released from the barrier.
 The count variable specifies how many threads are currently waiting at the barrier.
 Both variables are declared with the static attribute to force access through
 initbarrier and waitbarrier. If successful, the initbarrier and waitbarrier
 functions return 0. If unsuccessful, these functions return a nonzero error code.

 */

#include <errno.h>
#include <pthread.h>
#include <stdio.h>

static pthread_cond_t bcond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t bmutex = PTHREAD_MUTEX_INITIALIZER;
static int count = 0;
static int limit = 0;

int initbarrier(int n) {              /* initialize the barrier to be size n */
    int error;

    if (error = pthread_mutex_lock(&bmutex))        /* couldn't lock, give up */
        return error;
    if (limit != 0) {                 /* barrier can only be initialized once */
        pthread_mutex_unlock(&bmutex);
        return EINVAL;
    }
    limit = n;
    return pthread_mutex_unlock(&bmutex);
}

int waitbarrier(void) {    /* wait at the barrier until all n threads arrive */
    int berror = 0;
    int error;

    if (error = pthread_mutex_lock(&bmutex))        /* couldn't lock, give up */
        return error;
    if (limit <=  0) {                       /* make sure barrier initialized */
        pthread_mutex_unlock(&bmutex);
        return EINVAL;
    }
    count++;
    while ((count < limit) && !berror)
        berror =  pthread_cond_wait(&bcond, &bmutex);
    if (!berror) {
        fprintf(stderr,"soner %d\n",
                (int)pthread_self());
        berror = pthread_cond_broadcast(&bcond);           /* wake up everyone */
        }
    error = pthread_mutex_unlock(&bmutex);
    if (berror)
        return berror;
    return error;
}

/* ARGSUSED */
static void *printthread(void *arg) {
    fprintf(stderr,"This is the first print of thread %d\n",
            (int)pthread_self());
    waitbarrier();
    fprintf(stderr,"This is the second print of thread %d\n",
            (int)pthread_self());
    return NULL;
}

int main(void) {
    pthread_t t0,t1,t2;

    if (initbarrier(3)) {
        fprintf(stderr,"Error initilizing barrier\n");
        return 1;
    }
    if (pthread_create(&t0,NULL,printthread,NULL))
        fprintf(stderr,"Error creating thread 0.\n");
    if (pthread_create(&t1,NULL,printthread,NULL))
        fprintf(stderr,"Error creating thread 1.\n");
    if (pthread_create(&t2,NULL,printthread,NULL))
        fprintf(stderr,"Error creating thread 2.\n");
    if (pthread_join(t0,NULL))
        fprintf(stderr,"Error joining thread 0.\n");
    if (pthread_join(t1,NULL))
        fprintf(stderr,"Error joining thread 1.\n");
    if (pthread_join(t2,NULL))
        fprintf(stderr,"Error joining thread 2.\n");
    fprintf(stderr,"All threads complete.\n");
    return 0;
}
like image 874
snr Avatar asked Sep 05 '25 02:09

snr


1 Answers

Due to spurious wake-ups pthread_cond_signal could wake up more than one thread.

Look for word "spurious" in pthread_cond_wait.c from glibc.


In waitbarrier it must wake up all threads when they all have arrived to that point, hence it uses pthread_cond_broadcast.

like image 178
Maxim Egorushkin Avatar answered Sep 08 '25 01:09

Maxim Egorushkin