Чтение онлайн

на главную - закладки

Жанры

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

Стивенс Уильям Ричард

Шрифт:

17 }

18 /* запись идентификатора: файл остается открытым, чтобы он был заблокирован */

19 snprintf(line, sizeof(line), "%ld\n", (long) getpid);

20 Ftruncate(pidfd, 0);

21 Write(pidfd, line, strlen(line));

22 /* основной текст программы демона… */

23 pause;

24 }

Открытие и блокирование файла

8-17 Демон создает однострочный файл, в который записывает свой идентификатор процесса. Этот файл открывается или создается, а затем делается попытка Заблокировать его на запись целиком. Если блокировку установить не удается, мы понимаем, что один экземпляр демона уже запущен, поэтому выводится сообщение об ошибке и программа завершает работу.

ПРИМЕЧАНИЕ

Во многих версиях Unix демоны записывают свои идентификаторы в файл. Solaris 2.6 хранит подобные файлы в каталоге /etc, a Digital Unix 4.0B и BSD/OS — в каталоге /var/run.

Запись идентификатора процесса в файл

18-21 Мы укорачиваем файл до 0 байт, а затем записываем в него строку с нашим идентификатором. Причина, по которой нужно укорачивать файл, заключается в том, что у предыдущего экземпляра демона идентификатор мог быть представлен более длинным числом, чем у данного, поэтому в результате в файле может образоваться смесь двух идентификаторов.

Вот результат работы программы из листинга 9.8:

solaris % onedaemon& запускаем первый экземпляр

[1] 22388

solaris % cat pidfile проверяем идентификатор

22388

solaris % onedaemon пытаемся запустить второй экземпляр

unable to lock pidfile, is onedaemon already running?

Существуют и другие способы предотвращения запуска нескольких экземпляров демонов, например семафоры. Преимущество данного метода в том, что многим демонам и так приходится записывать в файл свои идентификаторы, а при досрочном завершении работы демона блокировка с файла снимается автоматически.

9.8. Блокирование файлов

Стандарт Posix.1 гарантирует, что если функция open вызывается с флагами O_CREAT (создать файл, если он еще не существует) и O_EXCL (исключающее открытие), функция возвращает ошибку, если файл уже существует. Более того, проверка существования файла и его создание (если он еще не существует) должны представлять собой атомарную по отношению к другим процессам операцию. Следовательно, мы можем использовать создаваемый таким методом файл как блокировку. Можно быть уверенным, что только один процесс сможет создать файл (то есть получить блокировку), а для снятия этой блокировки файл можно удалить командой unlink.

В листинге 9.9 приведен текст наших функций установки и снятия блокировки, использующих этот метод. При успешном выполнении функции open мы считаем, что блокировка установлена, и успешно возвращаемся из функции my_lock. Файл мы закрываем, потому что его дескриптор нам не нужен. О наличии блокировки свидетельствует само существование файла вне зависимости от того, открыт он или нет. Если функция open возвращает ошибку EEXIST, значит, файл существует и мы должны еще раз попытаться открыть его. 

У этого метода есть три недостатка.

1. Если процесс, установивший блокировку, завершится досрочно, не сняв ее, файл не будет удален. Существуют способы борьбы с этой проблемой, например проверка времени доступа к файлу и удаление его спустя некоторый определенный промежуток времени, — но все они несовершенны. Другое решение заключается в записи в файл идентификатора процесса, чтобы другие процессы могли считать его и проверить, существует ли еще такой процесс. Этот метод также несовершенен, поскольку идентификатор может быть использован повторно.

В такой ситуации лучше пользоваться блокировкой fcntl, которая автоматически снимается по завершении процесса.

2. Если файл открыт каким-либо другим процессом, мы должны еще раз вызвать open, повторяя эти вызовы в бесконечном цикле. Это называется опросом и является напрасной тратой времени процессора. Альтернативным методом является вызов sleep на 1 секунду, а затем повторный вызов open (этапроблема обсуждалась в связи с листингом 7.4).

Эта проблема также исчезает при использовании блокировки fcntl, если использовать команду F_SETLKW. Ядро автоматически приостанавливает выполнение процесса до тех пор, пока ресурс не станет доступен.

3. Создание и удаление файла вызовом open и unlink приводит к обращению к файловой системе, что обычно занимает существенно больше времени, чем вызов fcntl (обращение производится дважды: один раз для получения блокировки, а второй — для снятия). При использовании fcntl программа выполнила 10000 повторов цикла с увеличением порядкового номера в 75 раз быстрее, чем программа, вызывавшая open и unlink.

Листинг 9.9. Функции блокировки с использованием open с флагами O_CREAT и O_EXCL

//lock/lockopen.c

1 #include "unpipc.h"

2 #define LOCKFILE "/tmp/seqno.lock"

3 void

4 my_lock(int fd)

5 {

6 int tempfd;

7 while ((tempfd = open(LOCKFILE, O_RDWR|O_CREAT|O_EXCL, FILE_MODE)) < 0) {

8 if (errno != EEXIST)

9 err_sys("open error for lock file");

10 /* блокировка установлена кем-то другим, повторяем попытку */

11 }

12 Close(tempfd); /* открыли файл, блокировка установлена */

13 }

14 void

15 my_unlock(int fd)

16 {

17 Unlink(LOCKFILE); /* снимаем блокировку удалением файла */

18 }

Есть еще две особенности файловой системы Unix, которые использовались для реализации блокировок. Первая заключается в том, что функция link возвращает ошибку, если имя новой ссылки уже существует. Для получения блокировки создается уникальный временный файл, полное имя которого содержит в себе его идентификатор процесса (или комбинацию идентификаторов процесса и потока, если требуется осуществлять блокировку между отдельными потоками). Затем вызывается функция link для создания ссылки на этот файл с каким-либо определенным заранее именем. После успешного создания сам файл может быть удален вызовом unlink. После осуществления работы с блокировкой файл с известным именем удаляется командой unlink. Если link возвращает ошибку EEXIST, поток должен попытаться создать ссылку еще раз (аналогично листингу 9.9). Одно из требований к этому методу — необходимо, чтобы и временный файл, и ссылка находились в одной файловой системе, поскольку большинство версий Unix не допускают создания жестких ссылок (результат вызова link) в разных файловых системах.

Поделиться:
Популярные книги

Тринадцатый III

NikL
3. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый III

Легат

Прокофьев Роман Юрьевич
6. Стеллар
Фантастика:
боевая фантастика
рпг
6.73
рейтинг книги
Легат

Вперед в прошлое 7

Ратманов Денис
7. Вперед в прошлое
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Вперед в прошлое 7

Чехов книга 3

Гоблин (MeXXanik)
3. Адвокат Чехов
Фантастика:
попаданцы
альтернативная история
аниме
6.00
рейтинг книги
Чехов книга 3

Кодекс Охотника. Книга III

Винокуров Юрий
3. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
7.00
рейтинг книги
Кодекс Охотника. Книга III

Воин-Врач

Дмитриев Олег
1. Воин-Врач
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
6.00
рейтинг книги
Воин-Врач

Источник

Билик Дмитрий Александрович
11. Бедовый
Фантастика:
юмористическое фэнтези
городское фэнтези
мистика
7.00
рейтинг книги
Источник

Тыл-фронт

Головин Андрей
Проза:
военная проза
проза прочее
5.00
рейтинг книги
Тыл-фронт

#НенавистьЛюбовь

Джейн Анна
Любовные романы:
современные любовные романы
6.33
рейтинг книги
#НенавистьЛюбовь

Наследие Маозари 2

Панежин Евгений
2. Наследие Маозари
Фантастика:
попаданцы
рпг
аниме
5.00
рейтинг книги
Наследие Маозари 2

Приказано выжить!

Малыгин Владимир
1. Другая Русь
Фантастика:
боевая фантастика
попаданцы
альтернативная история
7.09
рейтинг книги
Приказано выжить!

Я князь. Книга XVIII

Дрейк Сириус
18. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я князь. Книга XVIII

Древесный маг Орловского княжества 4

Павлов Игорь Васильевич
4. Орловское княжество
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Древесный маг Орловского княжества 4

Пламенев. Книга 3-7

Карелин Сергей Витальевич
Пламенев
Фантастика:
аниме
уся
фэнтези
сянься
5.00
рейтинг книги
Пламенев. Книга 3-7