C 언어에서 SIGALRM을 활용한 타이머 이벤트 구현 방법

C 언어에서 타이머 이벤트를 구현할 때 SIGALRM은 매우 유용한 도구입니다. SIGALRM은 프로세스에 특정 시간 후 알림 신호를 보내는 메커니즘으로, 타이머 기반 작업을 수행하거나 주기적인 작업을 예약할 때 활용됩니다. 본 기사에서는 SIGALRM의 개념부터 기본 함수 사용법, 핸들러 작성, 실제 응용 예시까지 단계적으로 설명하여 SIGALRM을 활용한 타이머 구현 방법을 익힐 수 있도록 돕습니다.

목차

SIGALRM의 개념과 동작 원리


SIGALRM은 POSIX 표준에서 제공하는 신호(Signals) 중 하나로, 프로세스에 특정 시간이 경과했음을 알리는 역할을 합니다. 이 신호는 alarm() 또는 setitimer() 함수로 설정한 타이머가 만료되었을 때 운영 체제에 의해 프로세스에 전달됩니다.

SIGALRM의 동작 원리

  1. 타이머 설정: 프로세스는 alarm()이나 setitimer() 함수를 사용하여 특정 시간을 설정합니다.
  2. 타이머 만료: 설정된 시간이 경과하면 SIGALRM 신호가 프로세스에 전달됩니다.
  3. 신호 처리: 프로세스는 미리 정의된 신호 핸들러를 통해 SIGALRM 이벤트를 처리합니다.

SIGALRM의 특징

  • 단일 신호: SIGALRM은 타이머 만료 시 한 번만 발생합니다(반복 타이머는 추가 설정 필요).
  • 프로세스 기반: SIGALRM은 프로세스 단위로 동작하며, 멀티스레드 환경에서는 신호가 특정 스레드에 전달될 수 있습니다.
  • 비동기 처리: SIGALRM 신호는 비동기적으로 발생하므로, 신호 처리 루틴에서 적절한 동기화가 필요합니다.

응용 예시

  • 타임아웃 구현: 특정 작업이 시간 제한 내에 완료되지 않았을 때 종료 처리.
  • 주기적인 작업 예약: 주기적으로 실행해야 하는 작업(반복 타이머와 함께 사용).
  • 리소스 모니터링: 제한 시간 내에 특정 리소스를 확인하거나 업데이트.

SIGALRM은 간단하지만 강력한 기능으로, 타이머 기반 이벤트를 처리할 때 매우 효과적으로 사용할 수 있습니다.

SIGALRM 설정을 위한 기본 함수

C 언어에서 SIGALRM 신호를 설정하려면 alarm() 또는 setitimer() 함수를 사용합니다. 두 함수 모두 타이머를 설정하고, 타이머가 만료되면 SIGALRM 신호를 발생시킵니다. 하지만 두 함수의 사용 방식과 특징은 다릅니다.

1. `alarm()` 함수


alarm() 함수는 간단히 초 단위로 타이머를 설정하는 함수입니다.

#include <unistd.h>

unsigned int alarm(unsigned int seconds);
  • 매개변수:
  • seconds: 타이머 만료까지의 시간(초 단위).
  • 반환값:
  • 이전에 설정된 타이머의 남은 시간(초).
  • 특징:
  • 한 번만 동작하는 타이머.
  • 기존 타이머를 덮어씁니다(새로운 호출 시 이전 타이머 취소).

예제:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void alarm_handler(int signum) {
    printf("SIGALRM received!\n");
}

int main() {
    signal(SIGALRM, alarm_handler);
    alarm(5);  // 5초 후 SIGALRM 발생
    pause();   // 신호를 대기
    return 0;
}

2. `setitimer()` 함수


setitimer() 함수는 초 단위뿐 아니라 마이크로초 단위로도 타이머를 설정할 수 있으며, 반복적인 타이머도 지원합니다.

#include <sys/time.h>

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
  • 매개변수:
  • which: 타이머 유형(ITIMER_REAL은 SIGALRM을 발생시킴).
  • new_value: 새로운 타이머 설정(구조체 itimerval 사용).
  • old_value: 이전 타이머 설정을 저장(선택 사항).
  • 반환값:
  • 성공 시 0, 실패 시 -1.

itimerval 구조체:

struct itimerval {
    struct timeval it_interval; // 반복 주기
    struct timeval it_value;    // 첫 타이머 만료 시간
};
struct timeval {
    time_t tv_sec;  // 초
    suseconds_t tv_usec;  // 마이크로초
};

예제:

#include <stdio.h>
#include <sys/time.h>
#include <signal.h>

void timer_handler(int signum) {
    printf("Timer expired!\n");
}

int main() {
    struct itimerval timer;
    signal(SIGALRM, timer_handler);

    // 2초 후 타이머 만료, 이후 1초마다 반복
    timer.it_value.tv_sec = 2;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL, &timer, NULL);
    while (1);  // 계속 실행
    return 0;
}

비교

함수단위반복 타이머 지원주요 용도
alarm()초 단위지원하지 않음간단한 단발성 타이머
setitimer()초 및 마이크로초지원함복잡하고 정밀한 타이머 설정

이 두 함수를 적절히 사용하면 SIGALRM 신호를 통해 타이머 이벤트를 효과적으로 처리할 수 있습니다.

SIGALRM 처리용 핸들러 함수 작성법

SIGALRM 신호가 발생하면 이를 처리하기 위해 신호 핸들러(Signal Handler)를 작성해야 합니다. 핸들러는 SIGALRM 이벤트를 감지하고, 타이머 만료 시 실행할 작업을 정의합니다.

1. 신호 핸들러 함수의 기본 구조


신호 핸들러는 signal() 또는 sigaction() 함수를 통해 등록합니다. 핸들러는 반드시 void를 반환하며, 신호 번호를 매개변수로 받습니다.

void handler(int signum) {
    // SIGALRM 발생 시 처리할 동작
}

2. `signal()`을 사용한 핸들러 등록


signal() 함수는 간단히 특정 신호에 대한 핸들러를 등록하는 방법입니다.

#include <signal.h>

void handler(int signum) {
    printf("SIGALRM received!\n");
}

int main() {
    signal(SIGALRM, handler);  // SIGALRM 핸들러 등록
    alarm(5);  // 5초 후 SIGALRM 발생
    pause();   // 신호 대기
    return 0;
}
  • 장점: 간단한 구현.
  • 단점: 일부 시스템에서는 핸들러 등록이 비표준적일 수 있음.

3. `sigaction()`을 사용한 핸들러 등록


sigaction() 함수는 보다 안전하고 세부적인 신호 처리 설정을 제공합니다.

#include <signal.h>
#include <stdio.h>

void handler(int signum) {
    printf("SIGALRM handled with sigaction!\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sa.sa_flags = 0;  // 기본 동작 설정
    sigemptyset(&sa.sa_mask);  // 추가 블록 신호 없음

    sigaction(SIGALRM, &sa, NULL);  // SIGALRM 핸들러 등록
    alarm(5);  // 5초 후 SIGALRM 발생
    pause();   // 신호 대기
    return 0;
}
  • 장점:
  • 신호 처리 동작에 대한 세부적인 제어 가능.
  • 여러 신호를 안전하게 처리할 수 있음.
  • 단점: 설정이 다소 복잡함.

4. 신호 핸들러 작성 시 주의사항

  • 비동기 안전 함수 사용: 신호 핸들러 내부에서 호출하는 함수는 반드시 비동기-안전(asynchronous-safe)이어야 합니다. 예를 들어, printf() 대신 write() 사용.
  • 핸들러는 간결하게 유지: 핸들러 내부에서 복잡한 작업이나 긴 시간을 소비하는 작업을 수행하면 신호 처리에 지연이 발생할 수 있습니다.
  • 신호 블록 관리: 중요한 작업 중 SIGALRM 처리를 막으려면 sigprocmask()를 사용해 신호를 블록할 수 있습니다.

5. 신호 핸들러와 멀티스레드


멀티스레드 환경에서는 신호가 특정 스레드에 전달될 수 있습니다. 이를 제어하려면 pthread_sigmask()를 사용하여 신호를 특정 스레드에서만 처리하도록 설정할 수 있습니다.

6. 완전한 예제

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int signum) {
    write(STDOUT_FILENO, "Timer expired!\n", 15);
}

int main() {
    signal(SIGALRM, handler);  // 핸들러 등록
    alarm(3);  // 3초 후 타이머 만료
    printf("Waiting for SIGALRM...\n");
    pause();  // 신호 대기
    return 0;
}

이와 같은 방식으로 SIGALRM 핸들러를 작성하고 등록하면, 타이머 만료 시 원하는 동작을 수행할 수 있습니다.

SIGALRM을 활용한 간단한 타이머 구현

SIGALRM을 사용하여 간단한 타이머를 구현하는 기본적인 예제를 살펴보겠습니다. 이 예제에서는 alarm() 함수를 사용하여 지정된 시간 후에 SIGALRM 신호가 발생하도록 설정하고, 신호 핸들러에서 알림 메시지를 출력합니다.

1. 예제 코드: 기본 타이머

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void timer_handler(int signum) {
    // SIGALRM 신호 발생 시 실행될 함수
    printf("Timer expired! SIGALRM received.\n");
}

int main() {
    // SIGALRM 신호에 대해 timer_handler 함수 등록
    signal(SIGALRM, timer_handler);

    printf("Setting a timer for 5 seconds...\n");
    // 타이머를 5초로 설정
    alarm(5);

    // 프로세스가 신호를 기다리도록 정지
    pause();

    printf("Timer handler completed.\n");
    return 0;
}

2. 실행 흐름

  1. alarm(5)로 5초 타이머를 설정합니다.
  2. pause() 함수는 SIGALRM 신호가 발생할 때까지 프로세스를 일시 정지합니다.
  3. 5초가 경과하면 SIGALRM 신호가 발생하고, timer_handler() 함수가 실행됩니다.
  4. 핸들러 실행 후 프로그램은 종료됩니다.

3. 주요 함수 설명

  • signal(SIGALRM, handler): SIGALRM 신호가 발생할 때 실행될 핸들러를 등록합니다.
  • alarm(seconds): 지정된 초(seconds) 후 SIGALRM 신호를 발생시킵니다.
  • pause(): SIGALRM 신호가 발생할 때까지 프로세스 실행을 멈춥니다.

4. 출력 결과


프로그램 실행 후 5초가 지나면 다음과 같은 메시지가 출력됩니다:

Setting a timer for 5 seconds...
Timer expired! SIGALRM received.
Timer handler completed.

5. 활용 가능성


이 간단한 타이머 구현은 다음과 같은 작업에서 활용할 수 있습니다:

  • 특정 시간 동안 작업을 대기시킬 때.
  • 타임아웃 기반 작업을 수행할 때.
  • 시간 경과를 기준으로 이벤트를 트리거할 때.

이 예제는 SIGALRM을 활용한 타이머 구현의 기초를 보여주며, 더 복잡한 타이머 기능으로 확장하는 기반을 제공합니다.

`setitimer()`로 반복 타이머 구현하기

SIGALRM을 활용하여 반복적인 타이머 이벤트를 구현하려면 setitimer() 함수를 사용합니다. 이 함수는 마이크로초 단위의 정밀한 시간 설정과 반복적인 타이머 동작을 지원합니다.

1. 반복 타이머 구현 예제


다음 코드는 2초 후 첫 타이머를 만료시키고, 이후 1초 간격으로 반복적으로 SIGALRM 신호를 발생시킵니다.

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

void timer_handler(int signum) {
    static int count = 0;
    count++;
    printf("Timer triggered! Count: %d\n", count);
}

int main() {
    struct itimerval timer;

    // SIGALRM 신호 핸들러 등록
    signal(SIGALRM, timer_handler);

    // 첫 타이머 만료 시간: 2초
    timer.it_value.tv_sec = 2;
    timer.it_value.tv_usec = 0;

    // 반복 주기: 1초
    timer.it_interval.tv_sec = 1;
    timer.it_interval.tv_usec = 0;

    // 타이머 설정
    setitimer(ITIMER_REAL, &timer, NULL);

    printf("Timer set! Waiting for events...\n");

    // 무한 대기
    while (1) {
        pause(); // SIGALRM 신호 대기
    }

    return 0;
}

2. 실행 흐름

  1. setitimer()로 첫 타이머 만료 시간을 2초로 설정합니다.
  2. 이후, 1초 간격으로 반복 타이머가 실행되도록 설정합니다.
  3. SIGALRM 신호가 발생할 때마다 timer_handler()가 호출됩니다.
  4. pause() 함수는 SIGALRM 신호를 기다리는 동안 프로세스를 대기 상태로 유지합니다.

3. 주요 함수와 구조체

  • setitimer(): 타이머를 설정하거나 업데이트합니다.
  • ITIMER_REAL: 실제 시간을 기준으로 SIGALRM 신호 발생.
  • struct itimerval: 타이머의 동작을 정의합니다.
  • it_value: 첫 타이머 만료 시간.
  • it_interval: 반복 주기.

`itimerval` 구조체 예시

필드설명예제 값
it_value.tv_sec첫 타이머 만료 시간(초)2
it_value.tv_usec첫 타이머 만료 시간(마이크로초)0
it_interval.tv_sec반복 주기(초)1
it_interval.tv_usec반복 주기(마이크로초)0

4. 출력 결과


2초 후부터 1초 간격으로 출력:

Timer set! Waiting for events...
Timer triggered! Count: 1
Timer triggered! Count: 2
Timer triggered! Count: 3
...

5. 활용 사례

  • 주기적인 작업 수행: 서버 상태 모니터링, 주기적 데이터 업데이트 등.
  • 정밀한 타이머 관리: 밀리초 단위 이상의 정밀한 타이머가 필요한 경우.
  • 이벤트 기반 프로세스 제어: 특정 시간마다 이벤트를 트리거하여 비동기 작업 처리.

6. 주의사항

  • 핸들러 내부에서 과도한 작업을 수행하면 타이머 간격이 정확하지 않을 수 있습니다.
  • 멀티스레드 환경에서는 신호가 특정 스레드에 전달될 수 있으므로 동기화 처리가 필요합니다.

이 예제를 기반으로 SIGALRM과 setitimer()를 활용한 고급 타이머를 구현할 수 있습니다.

SIGALRM과 멀티스레드 환경

SIGALRM 신호는 멀티스레드 프로그램에서 사용할 때 몇 가지 주의사항이 필요합니다. SIGALRM은 프로세스 단위로 동작하기 때문에, 멀티스레드 환경에서는 예상치 못한 동작이 발생할 수 있습니다. 적절한 제어와 동기화를 통해 SIGALRM을 안전하게 사용할 수 있습니다.

1. SIGALRM의 기본 동작과 멀티스레드

  • SIGALRM은 프로세스의 주 스레드 또는 신호를 처리할 수 있는 스레드로 전달됩니다.
  • 멀티스레드 환경에서 어떤 스레드가 신호를 처리할지 명확하지 않을 수 있습니다.
  • 특정 스레드가 신호를 전담하도록 설정하려면 신호 마스크(pthread_sigmask())를 사용해야 합니다.

2. 신호를 특정 스레드로 제한하기


pthread_sigmask()를 사용하면 특정 스레드에서만 SIGALRM 신호를 처리하도록 설정할 수 있습니다.

#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>

void* signal_handler_thread(void* arg) {
    sigset_t sigset;
    int signum;

    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);

    while (1) {
        // SIGALRM 신호 대기
        sigwait(&sigset, &signum);
        if (signum == SIGALRM) {
            printf("SIGALRM received in thread!\n");
        }
    }
    return NULL;
}

int main() {
    pthread_t thread;
    sigset_t sigset;

    // 모든 스레드에서 SIGALRM 블록
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);
    pthread_sigmask(SIG_BLOCK, &sigset, NULL);

    // 신호 처리 전용 스레드 생성
    pthread_create(&thread, NULL, signal_handler_thread, NULL);

    // 타이머 설정
    alarm(3);  // 3초 후 SIGALRM 발생

    // 메인 스레드는 다른 작업 수행 가능
    printf("Main thread is doing other work...\n");

    pthread_join(thread, NULL);
    return 0;
}

3. 실행 흐름

  1. 모든 스레드에서 SIGALRM 신호를 차단(pthread_sigmask())합니다.
  2. 신호 처리 전용 스레드를 생성하고, sigwait()로 SIGALRM 신호를 처리합니다.
  3. 타이머가 만료되면 SIGALRM 신호는 전용 스레드로 전달됩니다.

4. 출력 결과

Main thread is doing other work...
SIGALRM received in thread!

5. SIGALRM과 멀티스레드 환경에서의 문제 해결

  • 신호 전달의 불확실성: 신호가 예상치 못한 스레드로 전달될 수 있습니다. 신호 마스크를 사용해 특정 스레드에서만 처리하도록 설정합니다.
  • 신호 핸들러와 동기화: 신호 핸들러가 글로벌 데이터를 수정하는 경우, 뮤텍스 등으로 동기화를 보장해야 합니다.
  • 타이머와 블록 작업의 혼합 사용: SIGALRM을 주기적으로 사용하는 경우, 블록 작업(I/O 등)과의 충돌을 피하기 위해 비동기 처리가 필요합니다.

6. 활용 사례

  • 멀티스레드 타이머 관리: 타이머 이벤트를 처리하는 전용 스레드를 통해 신호 관리.
  • 타임아웃 제어: 각 스레드에서 특정 작업에 대한 타임아웃을 별도로 설정.
  • 리소스 감시: 주기적인 SIGALRM 신호로 스레드 간 리소스 상태를 동기화.

SIGALRM은 멀티스레드 환경에서 적절히 제어하고 사용할 경우 강력한 도구로 활용될 수 있습니다.

SIGALRM 디버깅 팁과 트러블슈팅

SIGALRM을 사용하는 프로그램에서는 예상치 못한 동작이나 신호 처리 문제로 인해 디버깅이 필요할 수 있습니다. SIGALRM은 비동기적으로 동작하므로, 디버깅 시 특별한 주의와 적절한 접근 방법이 요구됩니다.

1. SIGALRM 디버깅 시 발생할 수 있는 주요 문제

  • 신호 처리 타이밍 이슈: 타이머가 정확한 시간에 작동하지 않거나 지연 발생.
  • 핸들러의 예상치 못한 동작: 핸들러에서 발생하는 오류로 프로그램이 비정상적으로 종료.
  • 멀티스레드 환경의 신호 처리 충돌: 신호가 예상치 못한 스레드에서 처리되는 문제.
  • 중첩된 신호 처리: SIGALRM이 발생 중에 다른 SIGALRM이 발생해 핸들러가 중첩 실행.

2. SIGALRM 디버깅 팁

1) 디버깅 메시지 추가


핸들러에서 printf() 대신 비동기 안전 함수인 write()를 사용해 디버깅 메시지를 출력합니다.

#include <unistd.h>
void handler(int signum) {
    write(STDOUT_FILENO, "SIGALRM received\n", 17);
}

2) 핸들러 동작 검증


핸들러가 호출되지 않을 경우, SIGALRM 신호가 올바르게 등록되었는지 확인합니다.

  • signal(SIGALRM, handler) 또는 sigaction() 호출 여부.
  • 신호 블록 상태 확인: sigprocmask()로 SIGALRM이 차단되었는지 확인.

3) 타이머 설정 검증


타이머가 올바르게 설정되었는지 확인합니다.

  • alarm() 또는 setitimer() 호출 후 반환값 확인.
  • getitimer()를 사용해 현재 타이머 설정 상태를 확인합니다.
struct itimerval timer;
getitimer(ITIMER_REAL, &timer);
printf("Remaining time: %ld sec, %ld usec\n", timer.it_value.tv_sec, timer.it_value.tv_usec);

4) 반복 타이머 중첩 방지


핸들러가 실행 중에 다른 SIGALRM 신호를 차단하여 중첩 문제를 방지합니다.

#include <signal.h>
void handler(int signum) {
    sigset_t block_set;
    sigemptyset(&block_set);
    sigaddset(&block_set, SIGALRM);
    sigprocmask(SIG_BLOCK, &block_set, NULL);

    // 핸들러 작업 수행
    write(STDOUT_FILENO, "SIGALRM handled\n", 16);

    // 신호 차단 해제
    sigprocmask(SIG_UNBLOCK, &block_set, NULL);
}

5) 멀티스레드 환경 문제 해결

  • pthread_sigmask()를 사용해 신호가 특정 스레드에서만 처리되도록 설정.
  • sigwait()로 신호를 명시적으로 대기하여 처리.

3. 트러블슈팅 사례

문제원인해결책
핸들러가 호출되지 않음신호 블록 설정 또는 핸들러 등록 누락sigprocmask()로 블록 상태 확인, 핸들러 등록
타이머가 정확히 작동하지 않음타이머 설정 값이 잘못됨getitimer()로 타이머 설정 확인
중첩된 SIGALRM 호출로 충돌 발생핸들러에서 SIGALRM을 차단하지 않음핸들러 내에서 SIGALRM 신호 차단
멀티스레드에서 신호 전달 문제신호가 임의의 스레드에서 처리됨pthread_sigmask()sigwait() 사용

4. 유용한 도구

  • GDB 디버거: SIGALRM이 발생할 때 중단점을 설정하여 신호 발생 시점을 분석.
  (gdb) handle SIGALRM stop
  • strace: SIGALRM 발생 및 처리 과정을 추적.
  strace -e signal ./program
  • Valgrind: 핸들러 내 메모리 접근 문제나 충돌 문제 확인.

5. 정리


SIGALRM 디버깅은 신호 핸들링의 비동기적 특성을 이해하고 적절한 도구와 접근 방식을 활용하면 효과적으로 문제를 해결할 수 있습니다. 핸들러의 간결한 설계와 신호 블록 제어는 디버깅 과정에서 매우 중요한 요소입니다.

실제 프로젝트에서 SIGALRM 활용 예시

SIGALRM은 타이머 기반 이벤트를 처리하는 데 유용하며, 실제 프로젝트에서 다양한 방식으로 활용할 수 있습니다. 아래에서는 SIGALRM을 활용한 두 가지 실제 프로젝트 예시를 소개합니다.


1. 네트워크 요청 타임아웃 구현

네트워크 프로그램에서 클라이언트 요청이 특정 시간 내에 응답하지 않을 경우 타임아웃을 설정해 연결을 종료하는 데 SIGALRM을 사용할 수 있습니다.

예제 코드:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>

void timeout_handler(int signum) {
    printf("Request timed out!\n");
    exit(1); // 프로그램 종료
}

int main() {
    signal(SIGALRM, timeout_handler);  // SIGALRM 핸들러 등록

    printf("Sending request...\n");
    alarm(5);  // 5초 타임아웃 설정

    // 네트워크 요청 시뮬레이션
    sleep(10);  // 응답 대기 (여기서는 응답이 늦음)

    // 요청 성공 시 타이머 취소
    alarm(0);
    printf("Request completed successfully.\n");

    return 0;
}

실행 결과:

  • 요청이 5초 안에 완료되지 않으면 SIGALRM이 발생하여 타임아웃 처리.
  • 타이머가 취소되지 않으면 Request timed out! 메시지 출력 후 종료.

2. 주기적인 시스템 상태 모니터링

서버 상태를 주기적으로 점검하거나, 로그 파일을 주기적으로 확인하여 이벤트를 기록하는 작업에 SIGALRM을 사용할 수 있습니다.

예제 코드:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

void monitor_handler(int signum) {
    printf("Monitoring system state...\n");
    // 시스템 상태 확인 코드
}

int main() {
    struct itimerval timer;

    // SIGALRM 핸들러 등록
    signal(SIGALRM, monitor_handler);

    // 3초 후 첫 실행, 이후 매 2초마다 반복
    timer.it_value.tv_sec = 3;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 2;
    timer.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL, &timer, NULL);  // 타이머 설정

    printf("System monitoring started...\n");
    while (1) {
        pause();  // SIGALRM 대기
    }

    return 0;
}

실행 결과:

System monitoring started...
Monitoring system state...
Monitoring system state...
Monitoring system state...
...

3. SIGALRM의 실제 활용 사례

  • 데이터베이스 백업: 주기적으로 백업 작업을 트리거.
  • 리소스 제한 구현: CPU 시간 제한을 초과한 작업 강제 종료.
  • 프로세스 시간 제어: 작업이 일정 시간 내에 완료되지 않으면 중단.
  • 주기적 상태 점검: 서버 상태, 로그 파일, 메모리 상태 등의 정기 확인.

4. SIGALRM 활용 시 고려사항

  • 정밀한 타이머 관리: 마이크로초 단위의 정밀도가 필요한 경우 setitimer() 사용.
  • 멀티스레드 환경: 신호를 특정 스레드에 전달하기 위해 신호 마스크 설정 필요.
  • 안전한 핸들러 설계: 핸들러에서의 작업은 간결하게 유지하고, 동기화를 보장해야 함.

SIGALRM은 단순하면서도 강력한 타이머 도구로, 실제 프로젝트에서 시간 기반 작업을 효율적으로 처리할 수 있는 방법을 제공합니다.

요약

본 기사에서는 C 언어에서 SIGALRM을 활용한 타이머 이벤트 구현 방법을 다뤘습니다. SIGALRM의 개념과 동작 원리, 기본 함수(alarm()setitimer()) 사용법, 핸들러 작성, 멀티스레드 환경에서의 사용법, 디버깅 팁, 그리고 실제 프로젝트 응용 사례를 통해 SIGALRM의 실용성을 강조했습니다.

SIGALRM은 타이머 기반 작업을 간단하고 효과적으로 구현할 수 있는 도구이며, 정확한 설정과 안전한 핸들러 설계를 통해 다양한 환경에서 유용하게 활용될 수 있습니다.

목차