потоками использовалась комбинация мьютекса с условной переменной (как видно из приведенного выше определения, типа pthread_barrier_t), освобождение блокированных потоков будет проходить по принципам, определенным для потоков, блокированных на условной переменной и получающих «широковещательное» (broadcast), или одновременное, освобождение. Документация QNX утверждает, что в таком случае первым будет «отпущен» тот поток, который ждал дольше других.

Функция ожидания на барьере возвращает значения:

BARRIER_SERIAL_THREAD — для первого из потоков, достигшего барьера и блокированного на нем;

0 — для всех последующих потоков;

EINVAL — при ошибке выполнения, которая может возникнуть только по некорректности инициализации барьера.

Блокировки чтения/записи

Блокировка чтения/записи является специфическим механизмом, отличающимся от рассмотренных выше. Специфика состоит в следующем:

• Данный тип блокировки даже по POSIX является альтернативным. Часто этот тип блокировки может реализовываться как надстройка над уже существующими базовыми примитивами. У. Стивенс [2] показывает один из вариантов такой «оберточной» реализации и приводит ссылки на еще несколько вариантов, в том числе и на предложенный стандартом IEEE 1996.

• Функциональность, обеспечиваемая блокировкой чтения/записи, может быть предоставлена и простым использованием других базовых механизмов, однако реализация с блокировкой чтения/записи может быть намного эффективнее по производительности приложения (как мы увидим позже).

Целесообразность привлечения блокировки чтения/записи возникает тогда, когда все множество потоков может быть отчетливо разделено на две группы: потоки, только считывающие защищаемые блокировкой данные (читатели), и потоки, модифицирующие эти данные (писатели). Такая ситуация традиционно возникает в области работы с объемными, сложно структурированными данными.

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

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

• Наличие множественных блокировок по чтению не препятствует (не блокирует) ни одному из потоков-читателей выполнять свои операции с ресурсом.

• Блокировка по записи может быть установлена, только если ни один поток не блокирует ресурс ни по чтению, ни по записи.

• Блокировка по записи запрещает дальнейшую блокировку ресурса (блокирует запрашивающий процесс) и по чтению, и по записи.

Функции работы с блокировками чтения/записи объявлены, как и большинство примитивов синхронизации, в заголовочном файле <pthread.h>.

Операции с блокировками чтения/записи

Инициализация объекта блокировки

int pthread_rwlock_init(pthread_rwlock_t* rwl,

 const pthread_rwlockattr_t* attr);

int pthread_rwlock_destroy(pthread_rwlock_t* rwl);

Вызов функций инициализирует/разрушает блокировку чтения/записи. При инициализации блокировки ей передается структура параметров блокировки pthread_rwlockattr_t, в которой могут устанавливаться параметры доступа к объекту из других процессов.

Вместо прямого вызова функции pthread_rwlock_init() для начальной инициализации статических блокировок чтения/записи (глобальных на уровне файла кода или пространства имен namespace либо явно описанных с квалификатором static) можно воспользоваться макросом PTHREAD_RWLOCK_INITIALIZER.

Захват блокировки чтения/записи

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

К первой группе относятся функции, допускающие рекурсивный захват объекта синхронизации и совместное использование участка кода. Это так называемые функции блокировки по чтению.

Вторая группа функций допускает только эксклюзивный захват объекта синхронизации и к выполнению защищаемого кода допускается только один поток. Это функции блокировки по записи.

Функции блокировки по чтению

int pthread_rwlock_rdlock(pthread_rwlock_t* rwl);

int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwl);

int pthread_rwlock_timedrdlock(pthread_rwlock_t* rwlock,

 const struct timespec* abs);

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

Первая функция в группе позволяет выполнить простой захват объекта синхронизации. При рекурсивном захвате с помощью любой из указанных функций необходимо помнить, что освобождение должно производиться столько же раз, сколько и захват.

Функция pthread_rwlock_rdlock() может возвращать следующие значения:

EOK — успешное выполнение;

EAGAIN — при первом использовании статически инициированной блокировки чтения/записи (PTHREAD_RWLOCK_INITIALIZER) недостаточно системных ресурсов для инициализации блокировки чтения/записи;

EDEADLK — вызывающий поток уже провел эксклюзивный захват (блокировку по

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату