Функция
Блокировка чтения-записи реализуется с помощью объектов типа pthread_rwlock_t. Этот же тип имеет атрибутный объект, который инкапсулирует атрибуты объекта блокировки. Функции установки и чтения атрибутов перечислены в табл. 5.5.
Объект типа pthread_rwlock_t может быть закрытым (для разделения между потоками одного процесса) или разделяемым (для разде
Таблица 5.4. Операции, используемые для блокировки ч
Инициализация
• int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
Запрос на блокировку
• int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
• int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
• int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
• int pthread_rwlock_timedwrlock( pthread_rwlock_t | *restrict rwlock, const struct timespec *restrict abs_timeout);
Освобождение блокировки
• int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
Тестирование блокировки
• int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
• int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
Разрушение
• int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
Таблица 5.5. Функции доступа к атрибутному объекту типа pthread_rwlock_t
• int pthread_rwlockattr_init (pthread_rwlockattr_t * attr); Инициализирует атрибутный объект блокировки чтения-записи,заданный параметром
• int pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr) Разрушает атрибутный объект б
• int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, int pshared); int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * restrict attr, int *restrict pshared); Устанавливает или возвращает атрибут
• PTHREAD_PROCESS_SHARED (разрешает б
• PTHREAD_PROCESS_PRIVATE (блокировка чтения-записи разделяется между потоками одного процесса)
Использование блокировок чтения-записи для реализации стратегии доступа
Блокировки чтения-записи можно использовать для реализации стратегии доступа CREW (параллельное чтение и исключающая запись). Согласно этой стратегии возможность параллельно считывать данные может быть предоставлена сразу нескольким задачам, но только одна задача получит право доступа для записи. При выполнении монопольной записи в этом случае не будет дано разрешение на параллельное чтение данных. Использование блокировок чтения-записи для защиты критических разделов продемонстрировано в листинге 5.3.
// Листинг 5.3. Пример использования потоками блокировок
// чтения-записи
//...
pthread_t ThreadA, ThreadB, ThreadC, ThreadD ; pthread_rwlock_t RWLock;
void *producerl(void *X) {
pthread_rwlock_wrlock(&RWLock) ; // Критический раэдел.
pthread_rwlock_unlock(&RWLock) ; return(0);
}
void *producer2 (void *X) {
pthread_rwlock_wrlock(&RWLock) ; // Критический раздел.
pthread_rwlock_unlock(&RWLock) ;
}
void *consumerl(void *X) {
pthread_rwlock_rdlock(&RWLock); // Критический раздел.
pthread_rwlock_unlock(&RWLock); return(0);
}
void *consumer2(void *X) {
pthread_rwlock_rdlock(&RWLock); // Критический раздел.
pthread_rwlock__unlock(&RWLock); return(0);
}
int main(void) {
pthread_rwlock_init(&RWLock,NULL); // Устанавливаем атрибуты мьютекса. pthread_create (&ThreadA, NULL, producerl, NULL) pthread_create(&ThreadB, NULL, consumerl, NULL) pthread_create (&ThreadC,NULL,producer2,NULL) pthread_create(&ThreadD,NULL, consumer2,NULL) //.. .
return(0);
}
В листинге 5.3 создаются четыре потока. Два потока, ThreadA и ThreadC, выполняют роль изготовителей, а остальные два (ThreadB и ThreadD) — потребителей. Все потоки имеют критический раздел, который защищается объектом блокировки чтения-записи RWLock. Потоки ThreadB и ThreadD могут входить в свои критические разделы параллельно или последовательно, но это исключено, если поток ThreadA или ThreadC пребывает в своем критическом разделе. Потоки ThreadA и ThreadC не могут входить в свои критические разделы параллельно. Частичная таблица решении для листинга 5.3 показана в табл. 5.6.
Таблица 5.6. Час