Книга: UNIX: взаимодействие процессов

Пример: блокировка на чтение при наличии в очереди блокировки на запись

Пример: блокировка на чтение при наличии в очереди блокировки на запись

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

Чтобы проверить, как эта ситуация разрешится при использовании блокировки записей fcntl, напишем тестовую программу, устанавливающую блокировку на чтение для всего файла и затем порождающую два процесса с помощью fork. 

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


Рис. 9.2. Определение возможности установки блокировки на чтение при наличиивочереди блокировки на запись

Листинг 9.6. Определение возможности установки блокировки на чтение при наличии в очереди блокировки на запись

//lock/test2.c
1  #include "unpipc.h"
2  int
3  main(int argc, char **argv)
4  {
5   int fd;
6   fd = Open("test1.data", O_RDWR | O_CREAT, FILE_MODE);
7   Read_lock(fd, 0, SEEK_SET, 0); /* родительский процесс блокирует весь файл на чтение */
8   printf("%s: parent has read lockn", Gf_time());
9   if (Fork() == 0) {
10   /* первый дочерний процесс */
11   sleep(1);
12   printf("%s: first child tries to obtain write lockn", Gf_time());
13   Writew_lock(fd, 0, SEEK_SET, 0); /* здесь он будет заблокирован */
14   printf("%s: first child obtains write lockn", Gf_time());
15   sleep(2);
16   Un_lock(fd, 0, SEEK_SET, 0);
17   printf("ls: first child releases write lockn", Gf_time());
18   exit(0);
19  }
20  if (Fork() == 0) {
21   /* второй дочерний процесс */
22   sleep(3);
23   printf("%s: second child tries to obtain read lockn", Gf_time());
24   Readw_lock(fd, 0, SEEK_SET, 0);
25   printf("%s: second child obtains read lockn", Gf_time());
26   sleep(4);
27   Un_lock(fd, 0, SEEK_SET, 0);
28   printf("%s: second child releases read lockn", Gf_time());
29   exit(0);
30  }
31  /* родительский процесс */
32  sleep(5);
33  Un_lock(fd, 0, SEEK_SET, 0);
34  printf("%s: parent releases read lockn", Gf_time());
35  exit(0);
36 }

Родительский процесс открывает файл и получает блокировку на чтение

6-8 Родительский процесс открывает файл и устанавливает блокировку на чтение для всего файла целиком. Обратите внимание, что мы вызываем read_lock (которая возвращает ошибку в случае недоступности ресурса), а не readw_lock (которая ждет его освобождения), потому что мы ожидаем, что эта блокировка будет установлена немедленно. Мы также выводим значение текущего времени функцией gf_time [24, с. 404], когда получаем блокировку.

Первый дочерний процесс

9-19 Порождается первый процесс, который ждет 1 секунду и блокируется в ожидании получения блокировки на запись для всего файла. Затем он устанавливает эту блокировку, ждет 2 секунды, снимает ее и завершает работу.

Второй дочерний процесс

20-30 Порождается второй процесс, который ждет 3 секунды, давая возможность первому попытаться установить блокировку на запись, а затем пытается получить блокировку на чтение для всего файла. По моменту возвращения из функции readw_lock мы можем узнать, был ли ресурс предоставлен немедленно или второму процессу пришлось ждать первого. Блокировка снимается через четыре секунды.

Родительский процесс блокирует ресурс 5 секунд

31-35 Родительский процесс ждет пять секунд, снимает блокировку и завершает работу.

На рис. 9.2 приведена временная диаграмма выполнения программы в Solaris 2.6, Digital Unix 4.0B и BSD/OS 3.1. Как видно, блокировка чтения предоставляется второму дочернему процессу немедленно, несмотря на наличие в очереди запроса на блокировку записи. Существует вероятность, что запрос на запись так и не будет выполнен, если будут постоянно поступать новые запросы на чтение. Ниже приведен результат выполнения программы, в который были добавлены пустые строки для улучшения читаемости:

alpha % test2
16:32:29.674453: parent has read lock
16:32:30.709197: first child tries to obtain write lock
16:32:32.725810: second child tries to obtain read lock
16:32:32.728739: second child obtains read lock
16:32:34.722282: parent releases read lock
16:32:36.729738: second child releases read lock
16:32:36.735597: first child obtains write lock
16:32:38.736938: first child releases write lock

Оглавление книги


Генерация: 1.307. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз