Как заставить Linux ждать, пока моя программа не завершит свое действие SIGTERM? - PullRequest
0 голосов
/ 21 мая 2019

Как заставить Linux ждать, пока моя программа на C ++ завершит свою процедуру очистки.Программа первоначально вызывает функцию sigaction(2), чтобы зарегистрировать пользовательский обработчик SIGTERM.Если протестировать обработчик, запустив kill -s TERM $(ps -C a.out -o pid=), у него не будет проблем.Тем не менее, в реальном закрытии другой случай.Иногда обработчик может выполнить свою работу, но иногда нет.Очевидно, что при выключении машины возникает состояние гонки.Кто-нибудь знает, как заставить систему подождать немного дольше, чтобы избежать состояния гонки?Спасибо.

1 Ответ

0 голосов
/ 25 мая 2019

В комментариях вы сказали, что используете MX Linux версии 18.2.Похоже, что он основан на Debian 9, который по умолчанию использует systemd, но все же имеет возможность вернуться к классическому SysVinit, если это необходимо.Веб-страницы MX Linux, кажется, подчеркивают пользовательский интерфейс и не упоминают ничего особенного о системе инициализации, поэтому я предполагаю, что она также использует systemd.

С systemd, механизм, называемый control groups (для краткости cgroups): когда systemd запускает сервис, он также помещает свой процесс в специальную cgroup.Эта cgroup автоматически наследуется любым процессом, запущенным службой.Когда systemd останавливает службу, она сначала выполнит любые пользовательские действия ExecStop, если они определены для службы, дождется TimeoutStopSec, и если в группе cgroup службы останутся какие-либо процессы, systemd отправитони SIGTERM, ждут другого TimeoutStopSec, а затем отправят SIGKILL для любых перенесенных процессов в cgroup.

То, что вас сбивает с толку, это, вероятно, тот факт, что пользовательские сессии такжеинкапсулировано в cgroup : все, что вы запускаете вручную, например, sh /etc/init.d/yourservice start, все равно будет учитываться как часть вашего пользовательского сеанса, даже если оно выполняет все действия, необходимые для классического демонизации.И поэтому, когда вы инициируете завершение работы, первое действие состоит в том, чтобы выйти из любых пользовательских сеансов ... что приводит к тому, что запущенная вручную служба сначала получает сигнал SIGHUP, затем SIGTERM после короткой задержки и, возможно, SIGKILL после другой короткой задержки.,Как только пользовательские сеансы будут очищены, произойдет остаток процесса выключения.

Чтобы успешно использовать init.d сценарии с systemd, вам необходимо знать несколько вещей.Механизм совместимости

systemd для сценариев init.d работает, автоматически генерируя собственный системный файл systemd .service для каждого сценария init.d, а затем используя эти файлы модулей точно так же, как собственные службы systemd,Это приводит к трем требованиям, с которыми вы можете быть незнакомы:

  • ваш сценарий init.d должен иметь стандартный комментарий в блоке Linux перед любыми строками без комментариев в сценарии, которые описывают зависимости от любых других служб.Это должно выглядеть примерно так (пример с сервера Dovecot IMAP):
### BEGIN INIT INFO
# Provides:          dovecot
# Required-Start:    $local_fs $remote_fs $network $syslog $time
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Should-Start:      postgresql mysql slapd winbind nslcd
# Should-Stop:       postgresql mysql slapd winbind nslcd
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Dovecot init script
# Description:       Init script for dovecot services
### END INIT INFO
  • После размещения скрипта init.d вы должны запустить systemctl daemon-reload, чтобы вызвать-run systemd-sysv-generator, который производит файл модуля, который будет вызывать ваш сценарий.

  • После помещения сценария в качестве /etc/init.d/yourservice и запуска systemctl daemon-reload, вы должны запустить службу, используялибо systemctl start yourservice, либо service yourservice start.Только эти методы заставляют systemd помещать ваш сервис в отдельную группу управления, что будет важно для упорядоченного завершения работы вашего сервиса.Запуск sh /etc/init.d/yourservice start не сделает этого.

Вы можете использовать systemctl cat yourservice для просмотра результирующего автоматически сгенерированного yourservice.service файла модуля.

Может быть, лучше написать собственный файл системного модуля systemd для вашей службы.Стандартные файлы модулей дистрибутива можно найти в каталоге /lib/systemd/system/;Вы можете использовать их в качестве примеров, но вместо этого вы должны поместить свой пользовательский файл модуля в /etc/systemd/system, чтобы файл модуля не был переопределен никакими обновлениями пакета.

...