Читаем Linux API. Исчерпывающее руководство полностью

Некоторые программы (в частности, многие демоны) должны следить за тем, чтобы они были запущены в единственном экземпляре. Обычно это достигается следующим образом: демон создает файл в стандартном каталоге и применяет к нему блокировку для записи. Он удерживает ее на протяжении всего своего существования и удаляет прямо перед завершением. Если попытаться запустить другой экземпляр того же демона, то он не сможет получить блокировку для соответствующего файла и автоматически завершится, понимая: один его экземпляр уже выполняется в системе.

Многие сетевые серверы используют другой принцип; чтобы узнать, выполняется ли в системе другой экземпляр сервера, они проверяют, занят ли их стандартный порт (см. раздел 57.10).

Для хранения таких файлов обычно применяется каталог /var/run. Как вариант местоположение файла может определяться конфигурацией демона.

Обычно демон записывает в заблокированный файл идентификатор своего процесса, так что в качестве расширения файла часто используется. pid (например, демон syslogd создает файл /var/run/syslogd.pid). Это удобно, если нужно найти PID демона, а также обеспечивает дополнительную меру предосторожности: можно проверить, существует ли процесс с таким идентификатором, воспользовавшись вызовом kill(pid, 0), как показано в разделе 20.5. (В старых реализациях UNIX, которые не поддерживали блокирование файлов, данный подход применялся в качестве неидеального, но достаточно практичного способа определения, действительно ли предыдущий экземпляр демона все еще работает, или он просто не сумел удалить этот файл перед завершением.)

Процедура создания и блокировки файла с идентификатором процесса может иметь множество мелких вариаций. Листинг 51.4 основан на принципе, описанном в книге [Stevens, 1999], и предоставляет функцию createPidFile(), которая инкапсулирует вышеописанные действия. Вызов данной функции в общем случае выглядит так:

if (createPidFile("mydaemon", "/var/run/mydaemon.pid", 0) == -1)

errExit("createPidFile");

В функции createPidFile() есть один неочевидный нюанс: использование вызова ftruncate() для удаления любой строки, которая могла находиться в файле до того. Это делается на случай, если предыдущий экземпляр демона не смог удалить файл — возможно, в результате системного сбоя. При возникновении такой ситуации, если идентификатор нового процесса слишком маленький, можно не полностью перезаписать старое содержимое файла. Например, если идентификатор равен 789, мы запишем в файл строку 789\n, но предыдущий экземпляр демона мог записать значение 12345\n. Без предварительного усечения файла результат выглядел бы как 789\n5\n. Иногда удаление любой существующей строки может и не понадобиться, но такой подход более аккуратен и исключает любую путаницу.

Аргументу flags можно передать константу CPF_CLOEXEC, заставляющую вызов createPidFile() установить для файлового дескриптора флаг FD_CLOEXEC (см. раздел 27.4). Это может пригодиться в серверных программах, которые перезапускают себя с помощью вызова exec(). Если не закрыть дескриптор во время данного вызова, то перезапущенный сервер будет считать, что в системе уже выполняется один его экземпляр.

Листинг 51.4. Создание PID-файла, который дает запустить только один экземпляр программы

filelock/create_pid_file.c

#include

#include

#include "region_locking.h" /* Для lockRegion() */

#include "create_pid_file.h" /* Объявляем createPidFile() и определяем CPF_CLOEXEC */

#include "tlpi_hdr.h"

#define BUF_SIZE 100 /* Достаточно большой для хранения PID в виде строки */

/* Открываем/создаем файл с именем 'pidFile', блокируем его, при необходимости

устанавливаем флаг FD_CLOEXEC для его дескриптора, записываем в него PID и (если

вызывающий процесс в этом заинтересован) возвращаем дескриптор, ссылающийся

на этот файл. Вызывающий процесс отвечает за удаление файла 'pidFile' прямо

перед завершением работы. Аргумент 'progName' должен содержать имя вызывающей

программы (argv[0] или нечто похожее); используется исключительно в диагностических

целях. Если мы не можем открыть файл 'pidFile' или сталкиваемся с какой-то другой

ошибкой, выводим в терминале соответствующее диагностическое сообщение. */

int

createPidFile(const char *progName, const char *pidFile, int flags)

{

int fd;

char buf[BUF_SIZE];

fd = open(pidFile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

if (fd == -1)

errExit("Could not open PID file %s", pidFile);

if (flags & CPF_CLOEXEC) {

/* Устанавливаем файловому дескриптору флаг FD_CLOEXEC */

flags = fcntl(fd, F_GETFD); /* Извлекаем флаги */

if (flags == -1)

errExit("Could not get flags for PID file %s", pidFile);

flags |= FD_CLOEXEC; /* Включаем FD_CLOEXEC */

if (fcntl(fd, F_SETFD, flags) == -1) /* Обновляем флаги */

errExit("Could not set flags for PID file %s", pidFile);

}

if (lockRegion(fd, F_WRLCK, SEEK_SET, 0, 0) == -1) {

if (errno == EAGAIN || errno == EACCES)

fatal("PID file '%s' is locked; probably "

"'%s' is already running", pidFile, progName);

else

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных