소개
일반적으로 백그라운드 서버 프로그램은 반드시 하나의 프로세스만 실행되어야 합니다. 그렇다면 단일 프로세스를 어떻게 구현할 수 있을까요?
이 예제에서는 flock 함수를 사용하여 /var/run/myservice.pid라는 PID 파일에 잠금을 적용합니다.
- 잠금이 실패하면 백그라운드 서비스 프로세스가 이미 실행 중이므로 오류 메시지를 출력하고 종료합니다.
- 잠금이 성공하면 백그라운드 서비스 프로세스가 실행 중이 아니므로 정상적으로 프로세스를 시작합니다.
백그라운드 서비스 단일 프로세스 제어
자세한 설명은 생략하고 바로 코드를 살펴보겠습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#define PID_BUFFER_SIZE (20)
#define PID_FILE_PATH "/var/run/myservice.pid"
// 서비스 프로세스 단일 인스턴스 실행 확인
// 반환값: 1--실행 중, 0--실행 중 아님, -1--오류 발생
int check_service_status()
{
int file_descriptor = open(PID_FILE_PATH, O_WRONLY|O_CREAT);
if(file_descriptor < 0)
{
printf("PID 파일 열기 오류(%d)! %s\n", errno, PID_FILE_PATH);
return -1;
}
// 파일 잠금 설정
// LOCK_SH 공유 잠금 설정. 여러 프로세스가 동일한 파일에 공유 잠금을 설정할 수 있습니다.
// LOCK_EX 배타적 잠금 설정. 하나의 파일에는 하나의 배타적 잠금만 설정할 수 있습니다.
if(flock(file_descriptor, LOCK_EX|LOCK_NB) == -1)
{
// 잠금 설정 실패, 서비스가 이미 실행 중임
printf("서비스가 현재 실행 중입니다! 오류 코드=%d\n", errno);
close(file_descriptor);
return 1;
}
// 잠금 성공, 서비스가 실행 중이 아님
// 파일 핸들러를 닫거나 잠금을 해제하지 마세요
// 프로세스가 종료되면 자동으로 잠금이 해제됩니다
printf("myservice가 실행 중이 아닙니다! 시작합니다..... PID=%ld\n", (long)getpid());
char pid_buffer[PID_BUFFER_SIZE] = {0};
snprintf(pid_buffer, sizeof(pid_buffer)-1, "%ld\n", (long)getpid());
// 프로세스 PID를 /var/run/myservice.pid 파일에 기록
write(file_descriptor, pid_buffer, strlen(pid_buffer));
return 0;
}
int main(void)
{
// 단일 인스턴스 실행 확인
if(0 != check_service_status())
{
printf("myservice 프로세스가 이미 실행 중입니다!!!!! 현재 프로세스를 종료합니다!\n");
return -1;
}
while(1)
{
printf("myservice 서비스 실행 중...\n");
sleep(2);
}
return 0;
}
실행 결과
프로그램을 실행하면 프로세스 PID가 7823임을 알 수 있습니다.
[root@linuxdev service]# ./myservice
서비스가 실행 중이 아닙니다! 시작합니다..... PID=7823
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
myservice 서비스 실행 중...
/var/run/myservice.pid 파일에도 해당 프로세스 PID가 기록되어 있으며, ps auxf | grep myservice 명령으로 myservice 프로세스가 계속 실행 중임을 확인할 수 있습니다.
[root@linuxdev service]# cat /var/run/myservice.pid
7823
[root@linuxdev service]#
[root@linuxdev service]# ps auxf | grep myservice
root 7823 0.0 0.0 3924 460 pts/0 S+ 00:32 0:00 | \_ ./myservice
root 9987 0.0 0.0 103256 856 pts/1 S+ 00:35 0:00 \_ grep myservice
[root@linuxdev service]#
이제 다시 myservice 프로그램을 실행하면 오류 메시지와 함께 종료됩니다. 이는 myservice 프로그램이 이미 실행 중이므로 다른 프로세스를 시작할 수 없다는 것을 의미하며, 이를 통해 백그라운드 서비스의 단일 프로세스 제어가 구현됩니다.
[root@linuxdev service]# ./myservice
서비스가 현재 실행 중입니다! 오류 코드=11
myservice 프로세스가 이미 실행 중입니다!!!!! 현재 프로세스를 종료합니다!