Остановка процесса и последующее его использование, не убивая - PullRequest
0 голосов
/ 15 марта 2019

Есть ли способ на языке программирования C остановить дочерний процесс, а затем вызвать его снова, чтобы начать с самого начала?Я понял, что если я использую SIGKILL и затем снова вызываю дочерний процесс, ничего не происходит.

void handler {
       printf(“entered handler”);
       kill(getpid(),SIGKILL);
}

int main () {
      pid_t child;
     child=fork();
      if (child<0) printf(“error”);
      else if (child==0) {
             signal(SIGINT,handler);
              pause();
     }
      else { 
           kill(child,SIGINT);
           kill(child,SIGINT);
      }

Это должно вывести два раза «Entered Handler», но это не так.Вероятно, потому что это не может снова вызвать ребенка.Могу ли я исправить это каким-то образом?

1 Ответ

1 голос
/ 15 марта 2019

Это должно напечатать два раза «Обработанный обработчик», но это не так. Возможно, потому что он не может снова вызвать ребенка.

Здесь есть несколько проблем, но общая неспособность доставить SIGINT дважды в один и тот же процесс не является одной из них. Проблемы включают в себя:

  • Обработчик сигнала выдает SIGKILL процессу, в котором он запущен, что вызывает немедленное завершение этого процесса. После завершения процесс не будет реагировать на дальнейшие сигналы, поэтому нет оснований ожидать, что ребенок когда-либо напечатает «введенный обработчик» дважды.
  • Существует состояние состязания между ребенком, устанавливающим обработчик для SIGINT, и родителем, посылающим ему этот сигнал. Если дочерний объект получает сигнал до установки обработчика для него, дочерний процесс завершит работу, не выдав какого-либо вывода.
  • Существует состояние гонки между первым сигналом, принимаемым ребенком, и вторым, доставляемым ему. Нормальные сигналы не ставятся в очередь, поэтому второй будет потерян, если доставлен, пока первый еще не получен.
  • Существует состояние гонки между блокировкой дочернего элемента в pause() и сигналом родителя. Если бы обработчик сигналов не убивал ребенка, тогда ребенок мог бы получить оба сигнала до того, как он дозвонится до pause(), и, следовательно, вообще не прервать его.
  • В случае, если ребенок сделал это, чтобы заблокировать в pause() до того, как родитель впервые сообщил об этом, и если он не совершил самоубийство, поставив себе SIGKILL, то сигнал должен заставить его разблокировать и вернуться из pause(), на пути к обычному завершению. Таким образом, тогда также может возникнуть состояние гонки между доставкой второго сигнала и нормальным прерыванием ребенка.
  • Функция printf() небезопасна для асинхронного сигнала. Вызов его из обработчика сигнала приводит к неопределенному поведению.
  • Вы должны всегда использовать sigaction() для установки обработчиков сигналов, а не signal(), потому что поведение signal() недостаточно определено и на практике различается. Единственное безопасное использование для signal() - сброс значения сигнала по умолчанию.

Могу ли я исправить это в как-нибудь?

  1. Удалить вызов kill() из обработчика сигнала.
  2. Заменить вызов printf() в обработчике сигналов на соответствующий вызов write().
  3. Используйте sigaction() вместо signal() для установки обработчика. Флаги по умолчанию должны соответствовать вашему использованию.
  4. Решите различные условия гонки,
    1. Наличие родительского блока SIGINT (через sigprocmask()) перед разветвлением, так что он будет изначально заблокирован в дочернем.
    2. Попросите ребенка использовать sigsuspend() с соответствующей маской сигнала вместо pause().
    3. Пусть ребенок отправит какой-то ответ родителю после возврата из sigsuspend() (возможно, это собственный сигнал или запись в канал, который родитель может прочитать), и попросите родителя дождаться этого ответа перед отправкой второй сигнал.
    4. Попросите ребенка позвонить sigsuspend() второй раз, чтобы получить второй сигнал.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...