在 C++ 中使用超时处理程序实现计时器

Posted

技术标签:

【中文标题】在 C++ 中使用超时处理程序实现计时器【英文标题】:Implementing timer with timeout handler in C++ 【发布时间】:2013-09-26 07:48:01 【问题描述】:

我需要在 C++ 中实现带有超时处理函数的计时器。 为此,我正在创建一个计时器,并使用类成员函数之一初始化 sigeventsigev_notify_function。下面是代码。

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 计时器应该在计时器到期后立即调用超时处理程序类的函数。请提出建议。

【问题讨论】:

对于超时函数类型 (TimerTimeoutHandler),请查看 std::function,而不是将其作为必须继承的类。有关如何使用std::function 的一些信息,请参阅this old answer of mine。 至于完全独立于平台的计时器解决方案,您可能需要查看例如this old answer of mine。在std::thread 中运行调度程序,它可以在任何具有 C++11 编译器的平台上使用。 How to pass member function to a function pointer?的可能重复 也结帐std::chrono。 【参考方案1】:

谢谢。我已经在链接 c++ timer implemetation - Assigning a member function to signal callback function pointer

的帮助下实现了我的计时器类

这里是代码

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

【讨论】:

以上是关于在 C++ 中使用超时处理程序实现计时器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中使用计时器在给定时间内强制输入?

nrf51822中app_button 的应用

C++回调定时器实现

多线程程序的 C++ 定时器中断

接口超时需要怎么处理

C#多线程之线程池篇3