13 Writew_lock(fd, 0, SEEK_SET, 0); /* здесь процесс будет заблокирован */
14 printf("%s: first child obtains write lock\n", Gf_time());
15 sleep(2);
16 Un_lock(fd, 0, SEEK_LET, 0);
17 printf("ls: first child releases write lock\n", Gf_time());
18 exit(0);
19 }
20 if (Fork() == 0) {
21 /* второй дочерний процесс */
22 sleep(3);
23 printf("ls: second child tries to obtain read lock\n", Gf_time());
24 Readw_lock(fd, 0, SEEK_SET, 0);
25 printf(%s: second child obtains read lock\n", Gf_time());
26 sleep(4);
27 Un_lock(fd, 0, SEEK_SET, 0);
28 printf("ls: second child releases read lock\n", Gf_time());
29 exit(0);
30 }
31 /* родительский процесс */
32 sleep(5);
33 Un_lock(fd, 0, SEEK_SET, 0);
34 printf("ls: parent releases write lock\n", Gf_time());
35 exit(0);
36 }
6-8 Родительский процесс создает файл и блокирует его целиком на запись.
9-19 Порождается первый процесс, который ждет одну секунду, а затем запрашивает блокировку на запись для всего файла. Мы знаем, что при этом процесс будет заблокирован, поскольку родительский процесс установил блокировку и снимет ее только через пять секунд, и мы хотим, чтобы этот запрос был помещен в очередь.
20-30 Порождается второй процесс, который ждет три секунды, а затем запрашивает блокировку на чтение на весь файл. Этот запрос будет также помещен в очередь.
И в Solaris 2.6, и в Digital Unix 4.0B мы видим, что блокировка на запись предоставляется первому процессу, как изображено на рис. 9.3. Но это еще не означает, что у запросов на запись есть приоритет перед запросами на чтение, поскольку, возможно, ядро предоставляет блокировку в порядке очереди вне зависимости от того, на чтение она или на запись. Чтобы проверить это, мы создаем еще одну тестовую программу, практически идентичную приведенной в листинге 9.7, но в ней блокировка на чтение запрашивается через одну секунду, а блокировка на запись — через три секунды. Эти две программы иллюстрируют, что Solaris и Digital Unix обрабатывают запросы в порядке очереди вне зависимости от типа запроса. Однако в BSD/OS 3.1 приоритет имеют запросы на чтение.
Рис. 9.3. Есть ли у писателей приоритет перед читателями
Вот вывод программы из листинга 9.7, на основании которого была составлена временная диaгрaммa на рис. 9.3:
alpha % test3
16:34:02.810285: parent has write lock
16:34:03.848166: first child tries to obtain write lock
16:34:05.861082: second child tries to obtain read lock
16:34:07.858393: parent releases write lock
16:34:07.865222: first child obtains write lock
16:34:09.865987: first child releases write lock
16:34:09.872823: second child obtains read lock
16:34:13.873822: second child releases read lock
9.7. Запуск единственного экземпляра демона
Часто блокировки записей используются для обеспечения работы какой-либо пpoгрaммы (например, демона) в единственном экземпляре. Фрагмент кода, приведенный в листинге 9.8, должен выполняться при запуске демона.
//lock/onedaemon.c
1 #include "unpipc.h"
2 #define PATH_PIDFILE "pidfile"
3 int
4 main(int argc, char **argv)
5 {
6 int pidfd;
7 char line[MAXLINE];
8 /* открытие или создание файла с идентификатором процесса */
9 pidfd = Open(PATH_PIDFILE, O_RDWR | O_CREAT, FILE_MODE);
10 /* попытка блокирования всего файла на запись */