3-13 Наш тип pthread_rwlock_t содержит одно взаимное исключение, две условные переменные, один флаг и три счетчика. Мы увидим, для чего все это нужно, когда будем разбираться с работой функций нашей программы. При просмотре или изменении содержимого этой структуры мы должны устанавливать блокировку rw_mutex. После успешной инициализации структуры полю rw_magic присваивается значение RW_MAGIC. Значение этого поля проверяется всеми функциями — таким образом гарантируется, что вызвавший поток передал указатель на проинициализированную блокировку. Оно устанавливается в 0 после уничтожения блокировки.
Обратите внимание, что в счетчике rw_refcount всегда хранится текущий статус блокировки чтения-записи: –1 обозначает блокировку записи (и только одна такая блокировка может существовать
в любой момент времени), 0 обозначает, что блокировка доступна и может быть установлена, а любое положительное значение соответствует количеству установленных блокировок на чтение.
14-17 Мы также определяем константу для статической инициализации нашей структуры.
Функция pthread_rwlock_init
Первая функция, pthread_rwlock_init, динамически инициализирует блокировку чтения-записи. Ее текст приведен в листинге 8.2.
7-8 Присваивание атрибутов с помощью этой функции не поддерживается, поэтому мы проверяем, чтобы указатель attr был нулевым.
9-19 Мы инициализируем взаимное исключение и две условные переменные, которые содержатся в нашей структуре. Все три счетчика устанавливаются в 0, а полю rw_magiс присваивается значение, указывающее на то, что структура была проинициализирована.
20-25 Если при инициализации взаимного исключения или условной переменной возникает ошибка, мы аккуратно уничтожаем проинициализированные объекты и возвращаем код ошибки.
Листинг 8.2. Функция pthread_rwlock_init: инициализация блокировки чтения-записи
9 if ((result = pthread_mutex_init(&rw->rw_mutex, NULL)) != 0)
10 goto err1;
11 if ((result = pthread_cond_init(&rw->rw_condreaders, NULL)) != 0)
12 goto err2;
13 if ((result = pthread_cond_init(&rw->rw_condwriters, NULL)) != 0)
14 goto err3;
15 rw->rw_nwaitreaders = 0;
16 rw->rw_nwaitwriters = 0;
17 rw->rw_refcount = 0;
18 rw->rw_magic = RW_MAGIC;
19 return(0);
20 err3:
21 pthread_cond_destroy(&rw->rw_condreaders);
22 err2;
23 pthread_mutex_destroy(&rw->rw_mutex);
24 err1:
25 return(result); /* значение errno */
26 }
Функция pthread_rwlock destroy
В листинге 8.3 приведена функция pthread_rwlock_destroy, уничтожающая блокировку чтения записи после окончания работы с ней.
8-13 Прежде всего проверяется, не используется ли блокировка в данный момент, а затем вызываются соответствующие функции для уничтожения взаимного исключения и двух условных переменных.
Листинг 8.З. Функция pthread_rwlock_destroy: уничтожение блокировки чтения-записи