Реализация таймера с обработчиком времени ожидания в C++

Мне нужно реализовать таймер с функцией обработчика времени ожидания в С++. Для этого я создаю таймер и инициализирую sigev_notify_function для sigevent одной из функций-членов класса. Ниже приведен код.

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;
}

Но во время компиляции я столкнулся с проблемой (это может быть проблема дизайна)

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)}’

Достаточно ли хороша эта конструкция, чтобы разделить реализацию таймера и реализацию обработчика тайм-аута? Я использую разные файлы .hpp и .cpp для всех определений и объявлений классов. Но для простоты я вставил весь код в два файла для лучшего понимания здесь.

Пожалуйста, посоветуйте хороший дизайн для реализации таймера. Класс таймера не должен зависеть от класса обработчика времени ожидания. В основном таймер UNIX должен вызывать функцию класса обработчика тайм-аута сразу после истечения срока действия таймера. Пожалуйста, предложите.


person Sandy    schedule 26.09.2013    source источник
comment
Для типа функции тайм-аута (TimerTimeoutHandler) посмотрите std::function вместо это как класс, который должен быть унаследован. См. этот мой старый ответ для получения некоторой информации о том, как использовать std::function.   -  person Some programmer dude    schedule 26.09.2013
comment
Что касается полностью независимого от платформы решения таймера, вы можете посмотреть, например. это мой старый ответ. Запустите диспетчер в std::thread, и его можно использовать на любой платформе, которая имеет компилятор C++11.   -  person Some programmer dude    schedule 26.09.2013
comment
Также проверьте std::chrono.   -  person miguel.martin    schedule 27.09.2013


Ответы (1)


Спасибо. Я реализовал свой класс таймера с помощью ссылки реализация таймера C++ — назначение функции-члена для сигнализации указателя функции обратного вызова

Вот код

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 );
}
person Sandy    schedule 27.09.2013