종료될 때마다 다시 시작되는 프로세스를 작성하는 방법

종료될 때마다 다시 시작되는 프로세스를 작성하는 방법

나는 정확히 그 반대를 원한다이 문제. 종료된 후에도 계속 다시 시작되는 프로세스를 만드는 방법을 알고 싶습니다. 누군가 나에게 구현 예를 줄 수 있습니까?

예를 들어, 다음과 같이 타임스탬프를 지속적으로 기록하고 카운터를 로그 파일에 증가시키는 간단한 프로세스가 있다고 가정해 보겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define FILE_PATH "/home/lincoln/date.log"

int main() {

    time_t current_time;
    struct tm *time_info;
    int counter = 0;

    while (1) {
        FILE *file = fopen(FILE_PATH, "a");
        if (file == NULL){
          perror("Failed to open the file");
          return 1;
        }
        // Get the current timestamp
        time(&current_time);
        time_info = localtime(&current_time);

        // Format the timestamp
        char timestamp[25];
        strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", time_info);

        // Write timestamp and counter to the file
        fprintf(file, "%s | Counter: %d\n", timestamp, counter++);
        fflush(file);

        fclose(file);
        sleep(5); // Sleep for 5 seconds
    }

    return 0;
}

바이너리 파일(ELF 파일)을 생성하기 위해 다음 명령을 사용했습니다.

gcc logger_file.c -o date_test

(이것은 단지 예일 뿐이라는 점에 유의하십시오. 지속적으로 인쇄하는 "hello world" 프로그램일 수 있습니다. 계속해서 실행되는 효과를 관찰하고 싶었기 때문에 로깅을 선택했습니다.)

~에서인용된 질문(내가 틀렸다면 정정해 주십시오.) 이는 하위 프로세스의 상위 프로세스를 모니터링하여 이를 수행합니다. 하위 프로세스가 종료되면 상위 프로세스가 이를 다시 시작합니다. 개념은 이해하지만 실제로 어떻게 구현되는지는 모르겠습니다.

제공된 바이너리 예제를 사용하여 이를 구현하는 방법을 보여줄 수 있는 사람이 있습니까? (내 연구에 대한 더 많은 링크도 환영합니다.)

더 많은 정보가 필요하면 알려주시기 바랍니다.

편집하다:내 구현에서는 임베디드 장치에서 수행할 계획입니다. 기본적으로 제가 일하는 환경에서는시스템 초기화부팅 시스템으로비지박스 v1.23.2armv7 프로세서에서 실행되는 3.18.44 커널의 도구 세트로 사용됩니다(저는 gcc-12-arm-linux-gnueabi-base도구 체인을 사용하고 있습니다).

답변1

프로세스가 종료되면 스스로 부활할 수 없습니다. 그것은 죽었고 실제로 더 이상 아무것도 할 수 없습니다(그게 요점입니다).

감독자가 프로세스 상태를 확인하고 이전 프로세스가 종료되면 새 프로세스를 생성하도록 할 수 있습니다.

거의 모든(일부 틈새 시장 또는 소규모 컨테이너 지향 제외) Linux 배포판은 이것을 간단하게 만듭니다. systemd가 이를 수행할 수 있으며, 해야 할 일은 systemd 서비스 단위 파일을 작성하고 설정하는 것뿐입니다.Restart=재산always, 또는 , on-abnormal또는 on-abort. 그게 다야!

그런 다음 systemd는 감독자 역할을 하며(procfs 등을 다루기 위해 자신의 감독자를 작성할 필요가 없음) 모든 것이 즉시 작동합니다.분명히서비스를 중지하여 다시 시작합니다 systemctl.

이제 실제로 이를 수행하는 방법을 묻습니다. procfs이것은 방법 중 하나라고 언급했습니다 . /proc/{PID} 디렉토리나 그 안의 메모리 맵을 살펴보세요.

그러나 규제 당국은대개그들이 하는 일은 (그리고 systemd의 service.c도 이것을 합니다) 핸들러를 등록하는 것입니다 SIGCHLD: 프로세스의 하위 프로세스가 종료되면 상위 프로세스가 신호를 받습니다. 이는 감독자가 실제로 감독 대상 프로세스를 하위 프로세스로 시작하기 때문에 fork작동합니다 .

따라서 대략 다음이 필요합니다.고대 오라클 가이드에서 느슨하게 적용됨그리고 Linux 매뉴얼 페이지는 다음과 같습니다 man waitpid.

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

void proc_exit() {
  int wstat;
  pid_t pid;

  while (1) {
    int retval = waitpid(pid, &wstat, WNOHANG);
    if (retval == 0)
      return;
    else if (retval == -1)
      return;
    else
      printf("Return code: %d\n", WEXITSTATUS(wstat));
  }
}
int main() {
  signal(SIGCHLD, proc_exit);
  switch (fork()) {
  case -1:
    perror("main: fork");
    exit(0);
  case 0:
    printf("I'm alive (temporarily)\n");
    exit(42);
  default:
    pause();
  }
}

하위 프로세스는 fork반환 0을 확인하므로 이는 인쇄 프로세스입니다 "I'm alive…. 여기에서 다른 실행 파일(즉, 감독되는 프로세스)을 생성하려면 를 호출하세요 execve.

답변2

init운이 좋게도 시스템에 일반 데몬이 있을 경우 에서 프로세스를 실행할 수 있습니다 /etc/inittab. 여기서 프로세스가 종료되면 다시 시작되도록 지정할 수 있습니다.

/etc/inittab다음과 같은 항목을 추가한 후 :

dtst:345:respawn:/path/to/date_time

이것은 dtst단지 레이블일 뿐입니다. 345즉, 런레벨 3, 4, 5에서 활성화되어 있으며 respawn프로세스가 종료되면(우리가 원하는 경우) 프로세스가 다시 시작된다는 의미입니다.

telinit그런 다음 명령을 사용 하거나 파일을 다시 읽으라고 kill -HUP 1지시하십시오 .init

systemd대신 를 사용하는 시스템에서 유사한 작업을 수행 하는 정교한 방법이 있을 수 있습니다 init.

BusyBox는 항목의 필드를 init무시합니다 . 필드는 비어 있지 않으면 컨트롤 TTY가 설정됩니다.runlevelsinittabid

또 다른 방법은 "nanny" 쉘 스크립트를 사용하여 이를 수행하는 것입니다.

#!/bin/sh

while true; do
  /path/to/date_test
done

프로그램이 정상적으로 종료되고 상태가 성공하면 루프가 종료되도록 설정할 수 있습니다.

while !/path/to/date_test; do : ; done

date_test프로그램이 실패하거나 비정상적으로 종료 되면 do-nothing null 명령을 실행 :하고 반복합니다.

그러나 이 루프를 실행하는 셸 자체는 종료로부터 보호되지 않습니다. 이는 프로그램이 불안정해지고 충돌이 발생하여 다시 시작해야 하는 경우에 유용합니다.

관련 정보