pthread_cond_signal может сделать более одного потока, чтобы проснуться? - PullRequest
2 голосов
/ 01 мая 2019

Я изучаю переменные состояния Pthread.Когда я читаю объяснение pthread_cond_signal, я вижу следующее:

Функция pthread_cond_signal() должна разблокировать хотя бы один потоков, которые заблокированы науказанная переменная условия cond (если какие-либо потоки заблокированы на cond).

До сих пор я знал, что pthread_cond_signal() будет вызывать только один поток за раз.Но цитируемое объяснение гласит хотя бы один .Что это значит?Может ли это сделать более одной нити проснуться?Если да, то почему pthread_cond_broadcast()?


En passant, я бы хотел, чтобы следующий код, взятый из UNIX Systems Programming из книги Роббинса , также был связан с моим вопросом.Есть ли какая-либо причина использования автором pthread_cond_broadcast() вместо pthread_cond_signal() в waitbarrier ? Как второстепенный вопрос, почему проверка !berror необходима также как часть предиката? Когда я пытаюсь изменить их оба, я не вижу никакой разницы.

/*

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

Ответы [ 2 ]

2 голосов
/ 01 мая 2019

Из-за ложных пробуждений pthread_cond_signal может пробудить более одного потока.

Ищите слово "ложное" в pthread_cond_wait.c из glibc.


В waitbarrier он должен разбудить все потоки, когда все они достигнут этой точки, следовательно, он использует pthread_cond_broadcast.

0 голосов
/ 01 мая 2019

Может ли [pthread_cond_signal()] вызвать более одного потока?

Это не гарантировано.В некоторых операционных системах, на некоторых аппаратных платформах при некоторых обстоятельствах может вызывать более одного потока. разрешено пробуждать более одного потока, потому что это дает разработчику большую свободу, позволяющую ему работать максимально эффективным образом для любого конкретного оборудования и ОС.

It must разбудить хотя бы один ожидающий поток, потому что иначе какой смысл его вызывать?

Но если вашему приложению нужен сигнал, который гарантированно разбудит все ожидающие потоки, то этодля чего pthread_cond_broadcast().


Эффективно использовать многопроцессорную систему сложно.https://www.e -reading.club / bookreader.php / 134637 / Herlihy, Shavit -_ The_art_of_multiprocessor_programming.pdf

Большинство стандартов языка программирования и библиотек допускают аналогичные свободы вповедение многопоточных программ по той же причине: чтобы позволить программам достигать высокой производительности на множестве различных платформ.

...