프로그래밍을 하다보면 메인 루트와 다르게 지속이며 일정주기로 어떤 일을 해야하는 경우가 있다.

     

      필자는 최근 CPP에서 타이머를 사용할 일이 있어 무심코 타이머를 적용했다가 난감한 일이 발생하였다. 필자가 진행하는 과제가 CPP기반으로 되어있는데다가 여러개의 구조가 합쳐진, 사실 이정도로 엉망스런 구조는 처음보긴 하는데 어쨋거나 장치 제조사에서 제공하는 라이브러리 및 소스패키지라 거의 손을 댈수도 없고 필요한 기능만 겨우 찾아논 상태였다. 더군다나 1개월만에 끝내라고해서 새로 찾아보고 빌드하는 것은 엄두도 못내는 상황이다.

     

      어쨋거나 필요한 기능에 대한 샘플을 모두 만들고 이제 합치면 되는데... 복잡한 구조로 만들어진 CMake에서 필자가 만든 타이머가 리얼타임 라이브러리(-lrt)를 필요로 하였다. 그래서 관련 라이브러 추가 설정을 했는데 빌드시 먹히지 않는다. 물론, 필자가 CMake를 거의 사용하지 않아서 그럴수도 있겠지만 몇시간동안 검색 했는데도 원하는 답변을 찾을 수 없었다. 반대로 필자와 비슷한 상황에 대한 문의만 있을 뿐... 게다가 이렇게 개차반 구조라면 손대기가 더 어려울 것 같기도 하다. 

     

    그래서 -lrt를 사용하지 않고 타이머를 구성하는 방법을 찾다보니 딱히.. 맘에 드는 것이 없었다. 필자 기억으로 예전에는 rt라이브러리를 사용하지 않고도 구현이 가능했던것 같은데 말이다. 그래서 소스를 조금 뒤져보니 해당 파일을 찾을 수 있었다. 그래서 시간나는데로 여러 사람이 구현한 타이머가 있다면 모아둬 볼까 한다. 언젠간 쓰겠지 이번처럼..

     

    우선 MFC와 비슷한 구조로 설정된 타이머이다. 하나 이상의 TimerID를 하나의 핸들러로 처리할 수 있도록 구성되어있다. 


    1. Timer with librt.so (-lrt)

    1.1. 샘플 코드

      샘플코드는 아래와 같이 작성한다. 1초에 한번씩 Run Send...를 출력하는 소스이다.

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

    timer_t timerSendID;


    static void timer_handler(int sig, siginfo_t *si, void *uc)
    {
        timer_t *tidp;
        tidp = si->si_value.sival_ptr;

        if(*tidp == timerSendID)
        {
            printf("Run Send...!\n");
        } else {
            printf("Etc Timer!\n");
        }
    }

    int create_timer(timer_t *timer_id, int sec, int msec)
    {
        int retv;

        // 시그널 처리를 위한 구조체 및 변수등록
        struct sigevent   tevt;
        struct itimerspec its;
        struct sigaction  sa;
        int signo = SIGRTMIN;

        // 핸들러 등록
        sa.sa_flags = SA_SIGINFO;
        sa.sa_sigaction = timer_handler;
        sigemptyset(&sa.sa_mask);

        retv=sigaction(signo, &sa, NULL);
        if(retv<0) {
            printf("Setup Failed : Sigaction\n");
            return -1;
        }

        // 시그널 설정 및 타이머 등록
        tevt.sigev_notify = SIGEV_SIGNAL;
        tevt.sigev_signo = signo;
        tevt.sigev_value.sival_ptr = timer_id;
        timer_create(CLOCK_REALTIME, &tevt, timer_id);

        its.it_interval.tv_sec = sec;
        its.it_interval.tv_nsec = msec * 1000000;
        its.it_value.tv_sec = sec;
        its.it_value.tv_nsec = msec * 1000000;
        timer_settime(*timer_id, 0, &its, NULL);  // 이 함수가 rt라이브러리를 요구한다.

        return 0;
    }


    int main(int argc, char** argv)
    {
        create_timer(&timerSendID, 1, 0);  // 타이머 생성 및 동작 시작.

        while(1) {
            ;
        }

        return 0;
    }

     

    1.2. 빌드. 

      컴파일은 gcc를 이용하여 컴파일 한다.  라이브러리를 추가하지 않으면 아래와 같이 참조오류가 발생된다.

    $ gcc -o timer timer.c 
    /usr/bin/ld: /tmp/ccr2FedD.o: in function `create_timer':
    timer.c:(.text+0xfc): undefined reference to `timer_create'
    /usr/bin/ld: timer.c:(.text+0x158): undefined reference to `timer_settime'
    collect2: error: ld returned 1 exit status

     

    3. 실행.

     따라서, rt라이브러리를 추가하여 컴파일 하자. 1초에 한번씩 메시지가 출력되는 것을 볼 수 있다.

    $ gcc -o timer timer.c -lrt
    $ ./timer
    Run Send...!
    Run Send...!
    Run Send...!
    Run Send...!
    ^C

     

     

    2. Timer

      리얼타임 라이브러리를 사용하지 않는 타이머이다. 

     

    2.1. 소스코드

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

    static void tmrSendHandler(int sig)   // 핸들러 구성
    {
        printf("Data Sending...\n");
    }

    int main(int argc, char **argv)
    {
        int retv;

        // 타이머 관련 구조체
        struct itimerval itv;
        struct sigaction sa;

        sigemptyset(&sa.sa_mask);

        // 핸들러 등록
        sa.sa_flags = 0;
        sa.sa_handler = tmrSendHandler;
        retv = sigaction(SIGALRM, &sa, NULL);
        if (retv == -1) {
            printf("Filed to register signal handler : sigaction\n");
            return retv;
        }

        // 시간설정 
        itv.it_value.tv_sec = 1;
        itv.it_value.tv_usec = 0;
        itv.it_interval.tv_sec = 1;
        itv.it_interval.tv_usec = 0;

        // 타이머 생성
        retv=setitimer(ITIMER_REAL, &itv, NULL);
        if (retv == -1)
        {
            printf("Timer setting error : setitimer\n");
            return retv;
        }

        while(1) {
             usleep(1);
        }

        return 0;
    }

     

    2.2. 빌드 및 실행

      복잡하게 사용하기에는 좀 단순하긴한데 그래도 내용도 짧고 해서 .. 

    pi@raspberrypi:~/works/exTimer $ gcc -o timer2 timer2.c 
    pi@raspberrypi:~/works/exTimer $ ./timer2
    Data Sending...
    Data Sending...
    Data Sending...
    Data Sending...

     

    라이브러리와 라이브러리를 사용하지 않는데는 차이가 여럿있을 것으로 예상된다. 현재로서는 확인하는데 필요한 시간이 부족하니 독자 스스로 알아보기바라며, 이후 시간이 나는데로 추가적인 구현방법을 더 찾으면서 관련 정보도 업데이트 하도록 하겠다. 현재 개발 스케줄에서 3일 지연중... 주말 출근.. 끙...

     

    반응형
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기