Читать интересную книгу UNIX: взаимодействие процессов - Уильям Стивенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 43 44 45 46 47 48 49 50 51 ... 128

Тип данных pthread_rwlock_t

В листинге 8.1[1] приведен текст заголовочного файла pthread_rwlock .h, в котором определен основной тип pthread_rwlock_t и прототипы функций, работающих с блокировками чтения и записи. Обычно все это находится в заголовочном файле <pthread.h>.

Листинг 8.1. Определение типа данных pthread_rwlock_t

//my_rwlock/pthread_rwlock.h

1  #ifndef __pthread_rwlock_h

2  #define __pthread_rwlock_h

3  typedef struct {

4   pthread_mutex_t rw_mutex; /* блокировка для структуры */

5   pthread_cond_t rw_condreaders; /* для ждущих читающих потоков */

6   pthread_cond_t rw_condwriters; /* для ждущих пишущих потоков */

7   int rw_magic; /* для проверки ошибок */

8   int rw_nwaitreaders;/* число ожидающих */

9   int rw_nwaitwriters;/* число ожидающих */

10  int rw_refcount;

11  /* –1, если блокировка на запись, иначе – количество блокировок на чтение */

12 } pthread_rwlock_t;

13 #define RW_MAGIC 0x19283746

14 /* порядок должен быть такой же, как у элементов структуры */

15 #define PTHREAD_RWLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER,

16  PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER,

17  RW_MAGIC, 0, 0, 0 }

18 typedef int pthread_rwlockattr_t; /* не поддерживается */

19 /* прототипы функций */

20 int pthread_rwlock_destroy(pthread_rwlock_t *);

21 int pthread_rwlock_init(pthread_rwlock_t *, pthread_rwlockattr_t *);

22 int pthread_rwlock_rdlock(pthread_rwlock_t *);

23 int pthread_rwlock_tryrdlock(pthread_rwlock_t *);

24 int pthread_rwlock_trywrlock(pthread_rwlock_t *);

25 int pthread_rwlock_unlock(pthread_rwlock_t *);

26 int pthread_rwlock_wrlock(pthread_rwlock_t *);

27 /* и наши функции-обертки */

28 void pthread_rwlock_destroy(pthread_rwlock_t *);

29 void pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t *);

30 void Pthread_rwlock_rdlock(pthread_rwlock_t *);

31 int Pthread_rwlock_tryrdlock(pthread_rwlock_t *);

32 int pthread_rwlock_trywrlock(pthread_rwlock_t *);

33 void pthread_rwlock_unlock(pthread_rwlock_t *);

34 void pthread_rwlock_wrlock(pthread_rwlock_t *);

35 #endif __pthread_rwlock_h

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: инициализация блокировки чтения-записи

//my_rwlock/pthread_rwlock_init.с

1  #include "unpipc.h"

2  #include "pthread_rwlock.h"

3  int

4  pthread_rwlock_init(pthread_rwlock_t *rw, pthread_rwlockattr_t *attr)

5  {

6   int result;

7   if (attr != NULL)

8    return(EINVAL); /* not supported */

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: уничтожение блокировки чтения-записи

//my_rwlock/pthread_rwlock_destroy.с

1  #include "unpipc.h"

2  #include "pthread_rwlock.h"

3  int

4  pthread_rwlock_destroy(pthread_rwlock_t *rw)

5  {

6   if (rw->rw_magic != RW_MAGIC)

7    return(EINVAL);

8   if (rw->rw_refcount != 0 ||

9    rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0)

10   return(EBUSY);

11  pthread_mutex_destroy(&rw->rw_mutex);

12  pthread_cond_destroy(&rw->rw_condreaders);

13  pthread_cond_destroy(&rw->rw_condwriters);

14  rw->rw_magic = 0;

15  return(0);

16 }

Функция pthread_rwlock_rdlock

Текст функции pthread_rwlock_rdlock приведен в листинге 8.4.

Листинг 8.4. Функция pthread_rwlock_rdlock: получение блокировки на чтение

//my_rwlock/pthread_rwlock_rdlock.с

1  #include "unpipc.h"

2  #include "pthread_rwlock.h"

3  int

4  pthread_rwlock_rdlock(pthread_rwlock_t *rw)

5  {

6   int result;

7   if (rw->rw_magic != RW_MAGIC)

8    return(EINVAL);

9   if ((result = pthread_mutex_lock(&rw->rw_mutex)) != 0)

10   return(result);

11  /* предпочтение отдается ожидающим разрешения на запись процессам */

12  while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) {

13   rw->rw_nwaitreaders++;

14   result = pthread_cond_wait(&rw->rw_condreaders, &rw->rw_mutex);

15   rw->rw_nwaitreaders--;

16   if (result != 0)

17    break;

18  }

19  if (result == 0)

20   rw->rw_refcount++; /* блокировка на чтение уже кем-то установлена */

21  pthread_mutex_unlock(&rw->rw_mutex);

22  return (result);

23 }

9-10 При работе со структурой pthread_rwl ock_t всегда устанавливается блокировка на rw_mutex, являющееся ее полем.

11-18 Нельзя получить блокировку на чтение, если rw_refcount имеет отрицательное значение (блокировка установлена на запись) или имеются потоки, ожидающие возможности получения блокировки на запись (rw_nwaitwriters больше 0). Если одно из этих условий верно, мы увеличиваем значение rw_nwaitreaders и вызываем pthread_cond_wait для условной переменной rw_condreaders. Вскоре мы увидим, что при разблокировании ресурса прежде всего проверяется наличие процессов, ожидающих возможности установить блокировку на запись, и если таковых не существует, проверяется наличие ожидающих возможности считывания. Если они имеются, для условной переменной rw_condreaders передается широковещательный сигнал.

19-20 При получении блокировки на чтение мы увеличиваем значение rw_refcount. Блокировка взаимного исключения после этого снимается.

ПРИМЕЧАНИЕ

В этой функции есть проблема: если вызвавший поток будет заблокирован в функции pthread_cond_wait и после этого его выполнение будет отменено, он завершит свою работу, не разблокировав взаимное исключение, и значение rw_nwaitreaders окажется неверным. Та же проблема есть и в функции pthread_rwlock_wrlock в листинге 8.6. Эти проблемы будут исправлены в разделе 8.5.

Функция pthread_rwlock_tryrdlock

В листинге 8.5 показана наша реализация функции pthread_rwlock_tryrdlock, которая не вызывает приостановления вызвавшего ее потока.

Листинг 8.5. Функция pthread_rwlock_tryrdlock: попытка заблокировать ресурс для чтения

//my_rwlock/pthread_rwlock_tryrdlock.с

1  #include "unpipc.h"

2  #include "pthread_rwlock.h"

3  int

4  pthread_rwlock_tryrdlock(pthread_rwlock_t *rw)

5  {

6   int result;

7   if (rw->rwjnagic != RW_MAGIC)

8    return(EINVAL);

1 ... 43 44 45 46 47 48 49 50 51 ... 128
На этом сайте Вы можете читать книги онлайн бесплатно русская версия UNIX: взаимодействие процессов - Уильям Стивенс.

Оставить комментарий