Зачем нам нужна проверка состояния перед pthread_cond_wait - программирование

Зачем нам нужна проверка состояния перед pthread_cond_wait

Я пытаюсь изучить основы pthread_cond_wait. Во всех применениях я вижу либо

if(cond is false)
   pthread_cond_wait

или

while(cond is false)
   pthread_cond_wait

Мой вопрос: мы хотим cond_wait только потому, что условие ложно. Тогда почему я должен принять боль от явного ввода цикла if/while. Я могу понять, что без проверки if/while до cond_wait мы сразу ударим, и он вообще не вернется. Является ли проверка состояния исключительно для решения этой цели или имеет какое-либо значение. Если он для решения ненужного условия ждет, то проверка состояния и избежание cond_wait похоже на опрос? Я использую cond_wait следующим образом.

void* proc_add(void *name){
    struct vars *my_data = (struct vars*)name;
    printf("In thread Addition and my id = %d\n",pthread_self());
    while(1){
    pthread_mutex_lock(&mutexattr);
    while(!my_data->ipt){  // If no input get in
            pthread_cond_wait(&mutexaddr_add,&mutexattr);  // Wait till signalled
            my_data->opt = my_data->a + my_data->b;
            my_data->ipt=1;
            pthread_cond_signal(&mutexaddr_opt);
    }
    pthread_mutex_unlock(&mutexattr);
    if(my_data->end)
            pthread_exit((void *)0);
    }
}

Логика заключается в том, что я прошу входной поток обрабатывать данные всякий раз, когда вход доступен, и сигнализировать выходной поток для его печати. ​​

4b9b3361

Ответ 1

Вам нужен цикл while, потому что поток, который вызвал pthread_cond_wait, может проснуться, даже когда условие, которого вы ожидаете, не достигнуто. Это явление называется "ложным wakepus".

Это может выглядеть как ошибка, но это то, как реализованы условные переменные.

Это также можно найти в man-страницах:

Поддельные пробуждения из pthread_cond_timedwait() или Возможны функции pthread_cond_wait(). Поскольку возврат из pthread_cond_timedwait() или pthread_cond_wait() не подразумевает что-нибудь о значении этого предиката, предикат должен быть переоценивается при таком возврате.

Обновление фактического кода:

void* proc_add(void *name) 
{
    struct vars *my_data = (struct vars*)name;

    printf("In thread Addition and my id = %d\n",pthread_self());

    while(1) {

        pthread_mutex_lock(&mutexattr);

        while(!my_data->ipt){  // If no input get in
            pthread_cond_wait(&mutexaddr_add,&mutexattr);  // Wait till signalled
        }

        my_data->opt = my_data->a + my_data->b;
        my_data->ipt=1;
        pthread_cond_signal(&mutexaddr_opt);

        pthread_mutex_unlock(&mutexattr);

        if(my_data->end)
            pthread_exit((void *)0);
        }
    }
}

Ответ 2

Вы должны проверить условие под мьютексом перед ожиданием, потому что сигналы переменной условия не поставлены в очередь (переменные условия не являются семафорами). То есть, если поток вызывает pthread_cond_signal(), когда нить не заблокирована в pthread_cond_wait() в этой переменной условия, тогда сигнал ничего не делает.

Это означает, что если у вас есть один поток, установите условие:

pthread_mutex_lock(&m);
cond = true;
pthread_cond_signal(&c);
pthread_mutex_unlock(&m);

а затем другой поток безоговорочно ждал:

pthread_mutex_lock(&m);
pthread_cond_wait(&c, &m);
/* cond now true */

этот второй поток будет блокироваться вечно. Этого можно избежать, проверив вторую проверку состояния:

pthread_mutex_lock(&m);
if (!cond)
    pthread_cond_wait(&c, &m);
/* cond now true */

Так как cond модифицируется только с помощью mutex m, это означает, что второй поток ожидает, если и только если cond является ложным.

Причина, по которой цикл while () используется в надежном коде вместо if (), объясняется тем, что pthread_cond_wait() не гарантирует, что он не проснется ложно. Использование while () также означает, что сигнализация переменной условия всегда абсолютно безопасна - "дополнительные" сигналы не влияют на правильность программы, а это означает, что вы можете делать такие вещи, как перемещение сигнала за пределами заблокированной секции кода.