리눅스 타이머 프로그래밍
- 프로그래밍/리눅스 프로그래밍
- 2023. 1. 15.
반응형
리눅스에서 타이머 파일 디스크립터를 이용하여 쓰레드 기반의 타이머 이벤트 처리 기능을 구현할 수 있다.
타이머에 대한 파일 디스크립터를 생성한 후, 해당 파일 디스크립터를 읽거나 폴링함으로써 타이머 이벤트를 획득하여 처리할 수 있다.
사용되는 함수는 timerfd_create(), timerfd_settime(), read()이다.
대략적인 절차는 다음과 같다.
1. timerfd_create() 함수를 호출하여 타이머 파일 디스크립터를 생성한다.
2. timerfd_settime() 함수를 호출하여 타이머 만기 주기를 설정한다.
3. 루프를 돌면서 read() 함수를 호출하여 타이머 이벤트를 처리한다. read() 함수 호출 시 블록되며, 타이머 만기 시점이 되면 리턴된다.
타이머를 설정할 때, 최초 타이머 주기와 두번째부터의 타이머 주기를 다르게 설정할 수 있다.
이는 각각 struct itimerspec 구조체의 it_value와 it_interval 변수에 설정된다.
함수 사용의 예제는 다음과 같다. 예제에서는 밀리초 단위의 타이머를 사용했지만, itimerspec 구조체가 나노초 단위까지 설정할 수 있으므로 나노초 단위의 타이머로도 사용할 수 있다.
// timer.c
#include <sys/timerfd.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#define INITIAL_DELAY (1000) ///< 최초 타이머 만기 지연 (밀리초 단위)
#define INTERVAL (100) ///< 타이머 만기 주기 (밀리초 단위)
pthread_t g_thread; ///< 타이머 이벤트 처리 쓰레드
/**
* @brief 타이머 이벤트 처리 쓰레드
* @param arg 사용되지 않음
* @return NULL
*/
static void * timer_thread(void *arg)
{
(void)arg;
/*
* 밀리초 단위 현재시각을 구한다.
*/
struct timespec current_ts;
clock_gettime(CLOCK_MONOTONIC, ¤t_ts);
int current_msec = (current_ts.tv_sec * 1000) + (current_ts.tv_nsec / 1000000);
struct itimerspec ts;
/*
* 최초 타이머 만기 시점을 설정한다. 만기시점 = 현재시각 + 지연
*/
int first_timer_exp_msec = current_msec + INITIAL_DELAY;
ts.it_value.tv_sec = first_timer_exp_msec / 1000;
ts.it_value.tv_nsec = (first_timer_exp_msec % 1000) * 1000000;
/*
* 타이머 주기를 설정한다.
*/
ts.it_interval.tv_sec = INTERVAL / 1000;
ts.it_interval.tv_nsec = (INTERVAL % 1000) * 1000000;
/*
* 타이머를 생성한다.
*/
int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
if (timer_fd < 0) {
perror("timerfd_create() ");
return NULL;
}
/*
* 타이머에 주기를 설정한다.
*/
int ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &ts, NULL);
if (ret < 0) {
perror("timerfd_settime() ");
return NULL;
}
/*
* 타이머 만기 이벤트를 처리한다.
*/
ssize_t s;
uint64_t exp;
while (1) {
s = read(timer_fd, &exp, sizeof(exp));
if (s == sizeof(exp)) {
/* TODO */
printf("Timer expired\n");
}
}
return NULL;
}
/**
* @brief 메인 함수
* @return int
*/
int main(void)
{
/*
* 타이머 처리 쓰레드를 생성한다.
*/
if (pthread_create(&g_thread, NULL, timer_thread, NULL) != 0) {
perror("pthread_create() ");
return -1;
}
/*
* 쓰레드 종료될 때까지 대기한다 (= 프로세스 종료 방지용)
*/
pthread_join(g_thread, NULL);
return 0;
}
다음과 같이 빌드한다.
gcc -o timer timer.c -lpthread
빌드된 파일을 실행하면 다음과 같이 주기적으로 출력되는 것을 확인할 수 있다.
root# ./timer
Timer expired
Timer expired
Timer expired
Timer expired
Timer expired
Timer expired
'프로그래밍 > 리눅스 프로그래밍' 카테고리의 다른 글
리눅스 타이머 프로그래밍 (2) | 2023.01.15 |
---|---|
리눅스 어플리케이션 반복 실행 테스트 방법 (1) | 2022.09.25 |
nanosleep() - 프로세스/쓰레드의 실행을 멈추는(재우는) 함수 (0) | 2022.04.20 |
Kernel PPS 신호 사용하기 (C source code) (0) | 2022.03.26 |
CURL 라이브러리 사용법 - 임베디드 플랫폼용으로 빌드하기(arm-cross-sysroot 활용) (0) | 2021.03.09 |
리눅스 TUN/TAP 디바이스 프로그래밍 (1) | 2021.01.28 |
프로세스 간 통신(IPC) 프로그래밍 - 메시지큐 (0) | 2021.01.19 |
GPSd를 이용한 GNSS 프로그래밍 (0) | 2020.12.24 |