프로세스 타이머와 알람 시스템
Sleeping과 Timer 개념
- Sleeping: 프로세스나 스레드가 실행을 대기하는 상태
- Timer: 프로세스가 자기 자신에게 알림을 스케줄하는 메커니즘
Alarms
unsigned int alarm(unsigned int seconds)
호출하는 프로세스가 지정된 seconds 이후에 SIGALRM 시그널을 받도록 설정한다.
동작 방식
- 기존 알람이 설정되어 있다면 새로운 알람으로 대체된다.
- 기존 알람의 남은 시간이 반환된다.
- seconds가 0이면 기존 알람을 취소한다.
시한 폭탄 예제
int left;
char *msg1 = "Beep\n";
char *msg2 = "Boom!\n";
void bomb(int sig) {
left--;
if(left) {
write(1, msg1, strlen(msg1));
alarm(1);
} else {
write(1, msg2, strlen(msg2));
_exit(0);
}
}
int main(int argc, char *argv[]) {
left = atoi(argv[1]);
signal(SIGALRM, bomb);
write(1, msg1, strlen(msg1));
alarm(1);
while (1) {
pause();
}
return 0;
}
Interval Timers (재귀적 알람)
alarm()의 일회성 문제를 해결하기 위한 기능이다.
Interval Timer 종류
- ITIMER_REAL: 실시간 기반으로 SIGALRM 시그널을 보냄
- ITIMER_VIRTUAL: 유저 코드 실행 시간을 기반으로 SIGVTALRM 시그널을 보냄
- ITIMER_PROF: 유저 + 커널 코드 실행 시간을 기반으로 SIGPROF 시그널을 보냄
struct itimerval
struct itimerval {
struct timeval it_interval; // 반복 알람 주기
struct timeval it_value; // 최초 알람 설정 시간
};
Interval Timer 설정
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
5초 이후 1초마다 실행되는 타이머 예제
void alarm_handler(int sig) {
write(1, "Timer hit!\n", 12);
}
int main() {
struct itimerval delay;
signal(SIGALRM, alarm_handler);
delay.it_value.tv_sec = 5;
delay.it_interval.tv_sec = 1;
setitimer(ITIMER_REAL, &delay, NULL);
while(1) pause();
return 0;
}
get Interval Timer
int getitimer(int which, struct itimerval *value)
- 성공 시 0 반환
- 실패 시 -1 반환
- which에 지정된 interval 타이머의 남은 시간이랑 interval 값을 가져와서 value에 저장한다.
- which가 다르면 다른 itimer에 등록된 타이머나 0초를 반환한다.
- itimer마다 고유한 타이머가 존재한다.
Interactions with alarm()
리눅스에서는 alarm()과 setitimer()는 각 프로세스의 timer를 공유한다. 즉, 서로 대체가 된다. 실시간 타이머(ITIMER_REAL)는 setitimer()와 alarm() 둘 중 하나만 설정하는 것이 권장된다.
POSIX Clocks 기반 Timer
setitimer()의 한계를 극복하는 방법으로 POSIX 타이머를 사용한다.
고전적인 Interval Timer의 한계
- 각 ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF 타입마다 1개씩만 타이머를 설정할 수 있다.
- 타이머가 만료됐다는 알림은 오직 타입마다 정해진 종류의 '시그널'을 통해 받을 수 있다.
- 해당 시그널이 block된 상태로 여러 번 울리면, pending되므로 block이 풀리고 시그널 핸들러가 한 번밖에 실행되지 않는다.
POSIX Timer 생성
int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid);
- clock_id: 사용할 시스템 시간 지정 (CLOCK_REALTIME, CLOCK_MONOTONIC 등)
- sigevent:
- SIGEV_NONE: 알림 없음
- SIGEV_SIGNAL: 특정 시그널을 보냄
- SIGEV_THREAD: 특정 함수 실행
- SIGEV_THREAD_ID: 특정 스레드에 시그널 전달
POSIX Timer 설정
int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspec *ovalue);
- flags: TIMER_ABSTIME 또는 0
- value: 타이머 설정 값
POSIX Timer 예제
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
void alarm_handler(int sig) {
write(1, "Timer hit!\n", sizeof("Timer hit!\n"));
}
int main() {
struct sigaction sa;
struct sigevent ev;
timer_t timer_id;
struct itimerspec delay;
sa.sa_handler = alarm_handler;
sigaction(SIGUSR1, &sa, NULL);
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGUSR1;
timer_create(CLOCK_MONOTONIC, &ev, &timer_id);
delay.it_value.tv_sec = 5;
delay.it_interval.tv_sec = 1;
delay.it_value.tv_nsec = 100;
delay.it_interval.tv_nsec = 100;
timer_settime(timer_id, 0, &delay, NULL);
while (1) pause();
}
반응형
'CS 지식 > 시스템 프로그래밍' 카테고리의 다른 글
[C언어] 프로세스 Sleep개념과 관련 시스템 콜(System call) (0) | 2025.03.02 |
---|---|
[C언어] 리눅스 Time과 Clock의 종류와 POSIX Clocks (0) | 2025.03.02 |
[C언어] 메모리 매핑 입출력(Memory Mapped I/O) 관련 시스템 콜(System call) (0) | 2025.03.02 |
[C언어] 다중화된 입출력(Multiplexed IO) 관련 시스템 콜(System call) (0) | 2025.03.02 |
[C언어] File I/O (Unix vs Standard IO)관련 시스템 콜(System call) (0) | 2025.03.02 |
댓글