pthread_sleepon_wait()

Заставить поток бездействовать на время ожидания

Прототип:

#include <pthread.h>
int pthread_sleepon_wait( const volatile void *addr );

Аргументы:

addr
Дескриптор, который поток должен ожидать. Значение addr обычно представляет собой структуру данных, управляющую ресурсом.

Библиотека:

libc

Описание:

Функция pthread_sleepon_wait() использует мьютекс и условные переменные чтобы "заснуть" на дескрипторе addr.

Функции pthread_sleepon_*() обеспечивают простой и унифицированный способ ожидания различных ресурсов в многопоточном приложении. Например, многопоточная файловая система может захотеть ожидать таких разнообразных вещей, как кэш-блок, блокировка файла, завершение операции и многие другие. Например, для ожидания ресурса:

pthread_sleepon_lock();
while ( (ptr = cachelist->free) == NULL )
{
pthread_sleepon_wait( cachelist );
}
cachelist->free = ptr->free;
pthread_sleepon_unlock();

Чтобы начать операцию и дождаться ее завершения:

/* Line up for access to the driver */
pthread_sleepon_lock();
if ( driver->busy )
{
pthread_sleepon_wait( &driver->busy );
}
/* We now have exclusive use of the driver */
driver->busy = 1;
driver_start(driver); /* This should be relatively fast */
/* Wait for something to signal driver complete */
pthread_sleepon_wait(&driver->complete);
pthread_sleepon_unlock();
/* Get the status/data */
driver_complete(driver);
/* Release control of the driver and signal anyone waiting */
pthread_sleepon_lock();
driver->busy = 0;
pthread_sleepon_signal(&driver->busy);
pthread_sleepon_unlock();
pthread_exit(NULL);

Рекомендуется тщательно выбирать, использовать ли цикл while:

При наличии сомнений лучше использовать цикл while, потому что он гарантирует доступ к нужному ресурсу.

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

"Пробуждение" выполняется, когда другой поток вызывает функцию pthread_sleepon_signal(), которая "пробуждает" единственный поток, или pthread_sleepon_broadcast(), которая "пробуждает" все потоки, заблокированные на addr. Потоки "пробуждаются" в порядке приоритета. Если имеется более одного потока с одинаковым наивысшим приоритетом, первым "пробуждается" тот, который ждал дольше всех.

Используется один мьютекс и одна условная переменная для каждого уникального адреса, который в настоящее время заблокирован. Таким образом, общее количество условных переменных равно количеству уникальных addr, ожидающих потока. Это также означает, что максимальное количество условных переменных никогда не превышает количество потоков. Для этого условные переменные создаются динамически по мере необходимости и помещаются во внутренний список для повторного использования, когда они не требуются.

Можно отметить, что функции pthread_sleepon_*() являются более простыми в использовании и понимании, чем условные переменные. Они также напоминают традиционные функции sleepon() и wakeup(), имеющиеся в ядрах Unix. Они могут быть реализованы следующим образом:

int _sleepon( void *addr )
{
int ret;
if ( (ret = pthread_sleepon_lock()) == EOK )
{
ret = pthread_sleepon_wait( addr );
pthread_sleepon_unlock();
}
return (ret);
}
void _wakeup( void *addr )
{
if ( pthread_sleepon_lock() == EOK )
{
pthread_sleepon_broadcast( addr );
pthread_sleepon_unlock();
}
}

Обратите внимание, что в большинстве ядер Unix поток выполняется до тех пор, пока не заблокируется, и поэтому ему не нужно беспокоиться о защите того условия, которое он проверяет с помощью мьютекса. Точно так же, когда вызывается Unix-овская wakeup(), немедленного переключения потока не происходит. Таким образом, можно использовать только описанные выше простые процедуры (_wakeup() и _sleepon()), если все потоки выполняются с планированием SCHED_FIFO и с одинаковым приоритетом, что более точно имитирует планирование ядра Unix.

Возвращаемое значение:

EOK
Успешное завершение.
EDEADLK
Вызывающий поток уже владеет управляющим мьютексом.

Классификация:

ЗОСРВ «Нейтрино»

Точка остановки потока
Да
Обработчик прерываний
Нет
Обработчик сигналов
Да
В потоке
Да

Тематические ссылки:

pthread_cond_wait(), pthread_cond_wait_interruptible(), pthread_mutex_lock(), pthread_mutex_unlock(), pthread_sleepon_broadcast(), pthread_sleepon_lock(), pthread_sleepon_signal(), pthread_sleepon_unlock(), sched_setscheduler()




Предыдущий раздел: Описание API системной библиотеки