Подтвердить что ты не робот

Понимание pthread_cond_wait() и pthread_cond_signal()

Вообще говоря, pthread_cond_wait() и pthread_cond_signal() называются ниже:

//thread 1:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
do_something()
pthread_mutex_unlock(&mutex);

//thread 2:
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);  
pthread_mutex_unlock(&mutex);

Этапы

  • pthread_cond_wait(&cond, &mutex);, он разблокирует мьютекс

  • Тема 2 блокирует мьютексы и вызывает pthread_cond_signal(), который открывает мьютексы

  • В потоке 1 вызывается pthread_cond_wait() и снова блокируется мьютекс

Теперь в потоке 2, после вызова pthread_cond_signal(), будет запущен pthread_mutex_unlock(&mutex), мне кажется, что он хочет разблокировать мьютекс, который теперь заблокирован потоком 1. Есть ли что-то не так в моем понимании

Кроме того, мне кажется, что pthread_cond_wait() может быть вызван только одним потоком для той же пары cond-mutex. Но есть высказывание "Функция pthread_cond_signal() должна разблокировать хотя бы один из потоков, которые блокируются при указанной переменной cond cond (если какие-либо потоки заблокированы на cond)". Таким образом, это означает, что pthread_cond_wait() может быть вызвано многими потоками для одной и той же пары cond-mutex?

4b9b3361

Ответ 1

pthread_cond_signal не разблокирует мьютекс (он не может, поскольку он не имеет ссылки на мьютексы, так как он мог знать, что разблокировать?) Фактически, сигнал не должен иметь никакого соединения с мьютексом; сигнальный поток не должен содержать мьютекс, хотя для большинства алгоритмов на основе переменных условия он будет.

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

Общее использование условий vars - это что-то вроде:

thread 1:
    pthread_mutex_lock(&mutex);
    while (!condition)
        pthread_cond_wait(&cond, &mutex);
    /* do something that requires holding the mutex and condition is true */
    pthread_mutex_unlock(&mutex);

thread2:
    pthread_mutex_lock(&mutex);
    /* do something that might make condition true */
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex);

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

Ответ 2

Вот типичный пример: поток 1 ждет условие, которое может выполняться потоком 2.

Мы используем один мьютекс и одно условие.

pthread_mutex_t mutex;
pthread_cond_t condition;

поток 1:

pthread_mutex_lock(&mutex); //mutex lock
while(!condition){
    pthread_cond_wait(&condition, &mutex); //wait for the condition
}

/* do what you want */

pthread_mutex_unlock(&mutex);

поток 2:

pthread_mutex_lock(&mutex);

/* do something that may fulfill the condition */

pthread_mutex_unlock(&mutex);
pthread_cond_signal(&condition); //wake up thread 1

Изменить

Как вы можете видеть в pthread_cond_wait руководство:

Он атомарно высвобождает мьютекс и заставляет вызывающий поток блокировать переменную condition cond; атомно здесь означает "атомарно относительно доступа другим потоком к мьютексу, а затем переменной условия".