3

I need to implement timer with timeout handler function in c++. For this I am creating a timer and I am initializing sigev_notify_function of sigevent with one of the class member function. Below is the code.

timer.hpp

#ifndef TIMERHELPER_H_
#define TIMERHELPER_H_

#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <iostream>

using namespace std;

#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1

typedef void (*TimerHandler)(sigval_t signum);

class TimerTimeoutHandler
{
    public:
        virtual void handlerFunction( void ) = 0;
};

class Timer
{
    public:
        Timer( TimerTimeoutHandler * timeHandler );
        ~Timer();

        void setDuration(long int seconds);
        void start();
        void restart();
        void timeout();
        void stop();

    private:
        void createTimer(timer_t *timerid, TimerHandler handler_cb);
        void startTimer(timer_t timerid, int startTimeout, int cyclicTimeout);
        void stopTimer(timer_t timerid);
        void timeOutHandler( sigval_t /* signum */ );

        long int m_Duration;
        TimerTimeoutHandler * timeOutHandlerImp;
        timer_t timerid;
};

class TimeTimeoutHandlerImp : public TimerTimeoutHandler
{
    public:
        TimeTimeoutHandlerImp(){}
        ~TimeTimeoutHandlerImp(){}

        void handlerFunction( void );
};

#endif /* TIMERHELPER_H_ */

timer.cpp

#include "timer.hpp"

Timer::Timer( TimerTimeoutHandler * timeHandler )
{
    timeOutHandlerImp = timeHandler;
    m_Duration = 0;

    createTimer( &timerid, timeOutHandler );
}

Timer::~Timer()
{
    stopTimer( timerid );
}

void Timer::setDuration(long int seconds)
{
    m_Duration = seconds;
}

void Timer::start()
{
    startTimer(timerid, m_Duration, 3);
}

void Timer::restart()
{
    stopTimer(timerid);
    startTimer(timerid, m_Duration, 0);
}

void Timer::stop()
{
    stopTimer(timerid);
}

void Timer::createTimer(timer_t *timerid, TimerHandler handler_cb)
{
    sigevent sev;
    pthread_attr_t attr;
    pthread_attr_init( &attr );
    sched_param parm;

    parm.sched_priority = 255;
    pthread_attr_setschedparam(&attr, &parm);

    sev.sigev_notify_attributes = &attr;
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = handler_cb;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = timerid;

    timer_create(CLOCKID, &sev, timerid);
}

void Timer::startTimer(timer_t timerid, int startTimeout, int cyclicTimeout)
{
    itimerspec its;

    /* Start the timer */
    its.it_value.tv_sec = startTimeout;
    its.it_value.tv_nsec = 0;

        /* for cyclic timer */
    its.it_interval.tv_sec = cyclicTimeout;
    its.it_interval.tv_nsec = 0;

    timer_settime(timerid, 0, &its, NULL);
}

void Timer::stopTimer(timer_t timerid)
{
    itimerspec its;
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    timer_settime(timerid, 0, &its, NULL);
}

void Timer::timeOutHandler( sigval_t /* signum */ )
{
    timeOutHandlerImp->handlerFunction();
}


void TimeTimeoutHandlerImp::handlerFunction( void )
{
    cout << "time handler invoked" << endl;
}

But during compilation I am facing problem (this could be design issue)

g++ timer.cpp 
timer.cpp: In constructor ‘Timer::Timer(TimerTimeoutHandler*)’:
timer.cpp:8:43: error: no matching function for call to ‘Timer::createTimer(void**, <unresolved overloaded function type>)’
timer.cpp:8:43: note: candidate is:
In file included from timer.cpp:1:0:
timer.hpp:35:14: note: void Timer::createTimer(void**, TimerHandler)
timer.hpp:35:14: note:   no known conversion for argument 2 from ‘<unresolved overloaded function type>’ to ‘TimerHandler {aka void (*)(sigval)}’

Is this design in good enough to decouple timer implementation and timeout handler implementation? I am using different .hpp and .cpp files for all class definition and declaration. But for simplicity I have pasted all code in two files for better understanding here.

Please advice good design for implementing the timer. Timer class should be independent of timeout handler class. Basically UNIX timer should invoke function of timeout handler class, immediately after timer expires. Please suggest.

Sandy
  • 159
  • 1
  • 2
  • 15
  • For the timeout function type (`TimerTimeoutHandler`) look into [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function) instead of having it as a class that must be inherited. See [this old answer of mine](http://stackoverflow.com/a/11866539/440558) for some information on how to use `std::function`. – Some programmer dude Sep 26 '13 at 07:50
  • As for a completely platform-independent timer solution, you may want to look at e.g. [this old answer of mine](http://stackoverflow.com/a/11866539/440558). Run the dispatcher in a [`std::thread`](http://en.cppreference.com/w/cpp/thread/thread), and it can be used on any platform which has a C++11 compiler. – Some programmer dude Sep 26 '13 at 07:53
  • possible duplicate of [How to pass member function to a function pointer?](http://stackoverflow.com/questions/4296281/how-to-pass-member-function-to-a-function-pointer) – n. m. could be an AI Sep 26 '13 at 08:02
  • Checkout [std::chrono](http://en.cppreference.com/w/cpp/chrono) too. – miguel.martin Sep 27 '13 at 06:31

1 Answers1

5

Thank you. I have implemented my timer class with help of link c++ timer implemetation - Assigning a member function to signal callback function pointer

Here is the code

timer.hpp

#ifndef TIMERHELPER_H_
#define TIMERHELPER_H_

#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <iostream>

using namespace std;

#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1

typedef void (*TimerHandler)(sigval_t signum);

class TimerTimeoutHandler
{
    public:
        virtual void handlerFunction( void ) = 0;
};

class Timer
{
    public:
        Timer( TimerTimeoutHandler * timeHandler );
        ~Timer();

        void setDuration(long int seconds);
        void start();
        void restart();
        void timeout();
        void stop();
        void callbackWrapper( void );
        static void timeOutHandler( sigval_t This  );

    private:
        void createTimer(timer_t *timerid, TimerHandler handler_cb);
        void startTimer(timer_t timerid, int startTimeout, int cyclicTimeout);
        void stopTimer(timer_t timerid);

    long int m_Duration;
        TimerTimeoutHandler * timeOutHandlerImp;
        timer_t timerid;
};

class TimeTimeoutHandlerImp : public TimerTimeoutHandler
{
    public:
        TimeTimeoutHandlerImp(){}
        ~TimeTimeoutHandlerImp(){}

        void handlerFunction( void );
};

#endif /* TIMERHELPER_H_ */

timer.cpp

#include "timer.hpp"
#include <unistd.h>

Timer::Timer( TimerTimeoutHandler * timeHandler )
{
    timeOutHandlerImp = timeHandler;
    m_Duration = 0;

    TimerHandler handler_cb = &timeOutHandler;
    createTimer( &timerid, handler_cb );
    //createTimer( &timerid, timeOutHandler );
}

Timer::~Timer()
{
    stopTimer( timerid );
}

void Timer::setDuration(long int seconds)
{
    m_Duration = seconds;
}

void Timer::start()
{
    startTimer(timerid, m_Duration, 3);
}

void Timer::restart()
{
    stopTimer(timerid);
    startTimer(timerid, m_Duration, 0);
}

void Timer::stop()
{
    stopTimer(timerid);
}

void Timer::createTimer(timer_t *timerid, TimerHandler handler_cb)
{
    sigevent sev;
    pthread_attr_t attr;
    pthread_attr_init( &attr );
    sched_param parm;

    parm.sched_priority = 255;
    pthread_attr_setschedparam(&attr, &parm);

    sev.sigev_notify_attributes = &attr;
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = handler_cb;
    sev.sigev_signo = SIG;
    sev.sigev_value.sival_ptr = this;

    timer_create(CLOCKID, &sev, timerid);
}

void Timer::startTimer(timer_t timerid, int startTimeout, int cyclicTimeout)
{
    itimerspec its;

    /* Start the timer */
    its.it_value.tv_sec = startTimeout;
    its.it_value.tv_nsec = 0;

        /* for cyclic timer */
    its.it_interval.tv_sec = cyclicTimeout;
    its.it_interval.tv_nsec = 0;

    timer_settime(timerid, 0, &its, NULL);
}

void Timer::stopTimer(timer_t timerid)
{
    itimerspec its;
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 0;
    its.it_interval.tv_nsec = 0;
    timer_settime(timerid, 0, &its, NULL);
}

void Timer::timeOutHandler( sigval_t This )
{
    Timer * timer = (Timer*) This.sival_ptr;
    timer->callbackWrapper();
}

void Timer::callbackWrapper( void )
{
    timeOutHandlerImp->handlerFunction();
    stopTimer( timerid );
}

void TimeTimeoutHandlerImp::handlerFunction( void )
{
    cout << "time handler invoked" << endl;
}

int main()
{
    TimeTimeoutHandlerImp * timerImp = new TimeTimeoutHandlerImp;
    Timer * timer = new Timer( timerImp );

    timer->setDuration( 5 );
    timer->start();
    sleep( 10 );
}
Community
  • 1
  • 1
Sandy
  • 159
  • 1
  • 2
  • 15