C의 다른 프로세스에서 데몬 프로세스 제어
이 기사에서는 C의 다른 프로세스에서 데몬 프로세스를 제어하는 방법에 대한 여러 방법을 소개합니다.
fork
및setsid
함수를 사용하여 데몬 프로세스 생성
데몬 프로세스에는 장기 실행 프로세스라는 몇 가지 특성이 있으며 시스템 시작시 데몬이 시작될 수 있습니다. 데몬 프로세스는 강제로 종료하거나 일시 중지하거나 시작시 비활성화하는 사용자 명령으로 제어 할 수 있습니다. 그러나 일반적인 시나리오에서는 일부 시스템 특정 스크립트를 사용하여 시스템 종료시 데몬이 종료됩니다. 데몬은 일반적으로 제어 터미널없이 백그라운드에서 실행되며 이러한 기능을 사용하는 프로그램은 외부 인터럽트를 처리하기 위해 다양한 신호 처리기를 구현해야합니다.
데몬 프로세스를 생성하고 모니터링하는 방법은 여러 가지가 있지만이 예제에서는 생성 단계를 보여줍니다. 여기서fork
함수를 호출하여 자식 프로세스를 생성합니다. 그런 다음 상위 프로세스가 종료되고 하위 프로세스가init
프로세스의 하위가되면서 계속 실행됩니다 (Linux 시스템에서init
프로세스는 시작시 첫 번째 프로세스 임). 하위 프로세스는setsid
함수를 호출하여 새 세션을 시작하고 제어 터미널에서 프로세스를 제거합니다. 마지막으로fork
를 다시 한 번 호출하고 부모 프로세스를 종료하여 데몬이 제어 터미널을 얻지 못하도록합니다. 이제 데몬 프로세스를 실행하고 있습니다. 시스템 또는 사용자가 해당 인터럽트를 전달할 때 리소스 정리 및 정상 종료를 수행하기 위해SIGTERM
신호 처리기를 등록하는 것이 중요합니다.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
void cleanupRoutine(int signal_number) {
write(STDERR_FILENO, "hello", 5);
_exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
fprintf(stderr, "[pid - %d] running...\n", getpid());
switch (fork()) {
case -1:
errExit("fork");
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
fprintf(stderr, "[pid - %d] running...\n", getpid());
if (setsid() == -1) errExit("setsid");
switch (fork()) {
case -1:
errExit("fork");
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
fprintf(stderr, "[pid - %d] running...\n", getpid());
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) {
perror("sigfillset");
exit(EXIT_FAILURE);
}
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) {
perror("sigaction SIGTERM");
exit(EXIT_FAILURE);
}
while (1) {
getpid();
}
exit(EXIT_SUCCESS);
}
daemon
함수를 사용하여 데몬 프로세스 만들기
앞의 예제는 겉보기에 올바른 코드를 보여 주지만 부모로부터 상속 된 모든 열린 파일 설명자를 닫는 단계가 없습니다. 작업 디렉토리가 변경되고 표준 입력을/dev/null
로 리디렉션하는 식입니다. 이 단계는 데몬이 특정 기능을 호출하더라도 특정 기능이 실패하지 않고 일부 이상한 동작이 관찰되지 않도록 보장합니다.
예를 들어, 터미널 창에서 이전 프로그램을 시작한 다음SIGTERM
신호를 데몬 프로세스로 보내면cleanupRoutine
신호 처리기의write
함수가 새 프롬프트가 표시된 후에도 동일한 터미널에 인쇄됩니다. 표시됩니다. 따라서daemon
함수는 GNU C 라이브러리에서 제공합니다. 새로 생성 된 데몬 프로세스에 대한 깨끗한 컨텍스트를 보장하기 위해 위 단계를 자동으로 처리합니다. daemon
함수는 두 개의 정수 인수를 사용합니다. 첫 번째 (0과 같으면) 현재 작업 디렉토리를 루트 디렉토리로 변경해야하는지 여부를 지정합니다. 표준 I/O 스트림이/dev/null
로 리디렉션되어야하는지 여부를 나타내는 두 번째 정수 (0과 같은 경우)입니다.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define errExit(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
void cleanupRoutine(int signal_number) {
write(STDERR_FILENO, "hello", 5);
_exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[]) {
fprintf(stderr, "[pid - %d] running...\n", getpid());
if (daemon(0, 0) == -1) errExit("daemon");
fprintf(stderr, "[pid - %d] running...\n", getpid());
struct sigaction sigterm_action;
memset(&sigterm_action, 0, sizeof(sigterm_action));
sigterm_action.sa_handler = &cleanupRoutine;
sigterm_action.sa_flags = 0;
// Mask other signals from interrupting SIGTERM handler
if (sigfillset(&sigterm_action.sa_mask) != 0) errExit("sigfillset");
// Register SIGTERM handler
if (sigaction(SIGTERM, &sigterm_action, NULL) != 0) errExit("sigaction");
while (1) {
getpid();
}
exit(EXIT_SUCCESS);
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook