Блокирует ли pthread_cond_wait мьютекс и ложное пробуждение - PullRequest
1 голос
/ 21 июня 2019

TL; DR

У меня есть домашняя работа, где мне нужно реализовать синхронизацию потоков.Во время реализации я был обеспокоен, если pthread_cond_wait() также блокирует мьютекс, если он внезапно просыпается, а не только, если он успешно просыпается.

Задача

Задача - это проблема работника / доставки, где естьрабочие потоки и потоки управления, которые обеспечивают заказы для рабочих.Для этого существует список заказов, из которого рабочие получают заказы, а поток управления вносит заказы.Список заказов является общим объектом и должен быть синхронизирован.

Мое решение до сих пор

Я думал, что для этой проблемы мне нужен монитор для списка, чтобы защитить его от доступа по пустоте или отдепозиты, когда он заполнен.

void deposit_order(order_list* ol, order* o){
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) >= MAX_ORDERS) {
        pthread_cond_wait(&(ol->cond_not_full), &(ol->mut_order_access));
    }

    ol->orders[ol->head] = o;
    ol->head = (ol->head+1)%MAX_ORDERS;
    ol->count++;

    pthread_cond_signal(&(ol->cond_not_empty));
    pthread_mutex_unlock(&(ol->mut_order_access));
}

order* get_order(order_list* ol) {
    pthread_mutex_lock(&(ol->mut_order_access));
    while(get_count(ol) <= 0) {
        pthread_cond_wait(&(ol->cond_not_empty), &(ol->mut_order_access));
    }
    order* o;

    o = ol->orders[ol->tail];
    ol->tail = (ol->tail+1)%MAX_ORDERS;
    ol->count--;

    pthread_cond_signal(&(ol->cond_not_full));
    pthread_mutex_unlock(&(ol->mut_order_access));
    return o;
}

Я считаю, что не так важно, что содержат структуры, поскольку тема - как синхронизировать доступ.Очевидно, структура order_list содержит mutex и две условные переменные, чтобы сигнализировать другой поток.Поэтому, если работник удаляет задачу из списка, он сигнализирует «не пусто» потоку управления, чтобы он мог разместить дополнительный заказ.Если руководство вносит заказ в виде сигналов «не пусто» рабочим потокам, то один поток может удалить заказ из списка.

Мои проблемы

Пока все хорошо, но теперь я думаю, что тамэто тот случай, когда вышеуказанное решение может быть критическим, и это «ложное пробуждение».Из этого потока я узнал, что поток не может внезапно активизироваться, если соответствующий мьютекс, а именно mut_order_access заблокирован другим потоком.Но что, если, например, в списке есть только один порядок, так что get_count(ol) >= MAX_ORDERS не выполняется, и поток внезапно выходит из режима ожидания, проверяет условие и помечает его как неверное и выпрыгивает из цикла.Затем другой поток получает сигнал и нормально просыпается, блокируя мьютекс после того, как предыдущий поток уже находится в критической области.Так что теперь оба потока будут в критической области, что приведет к сбою.

Вопрос

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

Ответы [ 2 ]

3 голосов
/ 21 июня 2019

Ваше понимание условий ложного пробуждения кажется неверным.Ложное пробуждение не имеет никакого отношения к тому, заблокирован ли мьютекс другим потоком.Если у вас нет программной ошибки (нарушение контрактов этих функций, общее повреждение памяти или другое неопределенное поведение и т. Д.), pthread_cond_wait никогда не сможет вернуться без удержания (блокировки) мьютекса вызывающим потоком.В случае ложного следа он все еще не может вернуться, пока мьютекс не будет восстановлен.Даже в случае отмены официанта с помощью pthread_cancel обработчик очистки отмены не может начать работать, пока мьютекс не будет повторно получен.

3 голосов
/ 21 июня 2019

Функция, которая может возвращаться с заблокированным или разблокированным мьютексом и которая не дает вам возможности определить разницу, будет совершенно непригодна для использования.Как вы могли узнать, разблокировать мьютекс или нет?

Функция pthread_cond_wait обеспечивает элементарную операцию "разблокировки и ожидания".Он всегда повторно получает мьютекс перед возвратом.Конечно, если вы не нарушаете ни одно из его предварительных условий.

Вы можете думать об этом как о трехэтапном процессе:

  1. Атомная разблокировка и ожидание.
  2. Либо другой поток сигнализирует / транслирует условие, либо происходит ложное пробуждение.
  3. Повторное получение мьютекса

* Только после выполнения всех трех шагов pthread_cond_wait возвращает,Ложное пробуждение происходит, когда ожидание заканчивается, когда другой поток не отправляет сигнал.

...