c++实现定时回调函数



我想用c++实现一些系统,这样我就可以调用一个函数,并要求在X毫秒内调用另一个函数。类似这样的东西:

callfunctiontimed(25, funcName);

25是应该调用函数之前的毫秒数。

我想知道是否需要多线程,然后使用一些延迟函数?除了使用函数指针之外,像这样的功能是如何工作的?

对于可移植的解决方案,可以使用boost::asio。下面是我不久前写的一个演示。您可以更改

t.expires_from_now(boost::posix_time::seconds(1));

为了适应您需要说在200毫秒后进行函数调用。

t.expires_from_now(boost::posix_time::milliseconds(200)); 

下面是一个完整的工作示例。它是反复呼叫的,但我认为只要稍微改变一下,就可以很容易地只呼叫一次。

#include <iostream>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::asio;
using namespace std;
class Deadline 
{
public:
Deadline(deadline_timer &timer) : t(timer) {
wait();
}
void timeout(const boost::system::error_code &e) {
if (e)
return;
cout << "tick" << endl;
wait();
}
void cancel() {
t.cancel();
}

private:
void wait() {
t.expires_from_now(boost::posix_time::seconds(1)); //repeat rate here
t.async_wait(boost::bind(&Deadline::timeout, this, boost::asio::placeholders::error));
}
deadline_timer &t;
};

class CancelDeadline {
public:
CancelDeadline(Deadline &d) :dl(d) { }
void operator()() {
string cancel;
cin >> cancel;
dl.cancel();
return;
}
private:
Deadline &dl;
};

int main()
{
io_service io;
deadline_timer t(io);
Deadline d(t);
CancelDeadline cd(d);
boost::thread thr1(cd);
io.run();
return 0;
}

//result:
//it keeps printing tick every second until you enter cancel and enter in the console
tick
tick
tick

很多人在这件事上都给出了很好的答案,但我会直接回答这个问题,因为几年前我也遇到过类似的问题。我不能使用Boost有几个原因——我知道Boost在很多开源软件中都有很好的用途。此外,我真的很想了解定时器和回调,因为它与基于Linux的环境有关。所以,我写了自己的。

从根本上讲,我有一个Timer类和一个TimerCallback类。一个典型的回调,作为TimerCallback类的继承类实现,将在回调时执行的操作放在triggered ()方法中,专门为需求实现。

根据通常的语义,Timer对象与回调对象相关联,回调对象可能包含执行回调所需的所有信息。定时器调度由一个环境范围的定时器minheap管理,它必须在一个单独的线程/进程中维护。这个minheap任务只做一件事:它minheap将来设置的回调事件的minheap。minheap选择O(1)中要激发的下一个事件,并且可以为n计时器事件minheap化O(log n)中的剩余事件。它还可以在O(log n)中插入一个新的计时器事件(在这里阅读对堆的温和介绍)。

当计时器触发时,minheap调度程序会检查它是周期性计时器、一次性计时器还是将执行特定次数的计时器。因此,计时器对象要么从minheap中删除,要么在下一次执行时重新插入minheap。如果要删除计时器对象,则将其从minheap中删除(但计时器对象的删除可能会也可能不会留给创建它的任务),堆的其余部分将被minheap化;即重新排列以满足minheap属性。

这里有一个可工作且经过单元测试的实现,可能包含错误(摘自我的应用程序),但我认为它可能会对某些人有所帮助。该实现基于多进程(fork()-ed进程)(在主任务(进程)中也使用pthreads),并使用POSIX共享内存和POSIX消息队列进行进程之间的通信。

是否希望它以异步方式执行,以便在25毫秒结束时执行回调,而不会阻塞主执行线程?如果是这样,您可以在独立于您实现的定时器/定时回调函数的线程中执行回调。

如果不使用多线程,则的main或调用函数callfunctiontimed(25,funcName);会在您运行sleep/usleep时阻塞。这是你的选择现在决定要实现什么行为。

真正的解决方案不会像多线程那样简单。考虑到函数可以用不同的超时和函数多次调用,您如何保留不同的定时器/回调信息。

一种方法是这样做的:

  1. 创建定时器/回调的排序列表,根据到期时间进行排序
  2. 有一个主线程和一个查看回调/定时器的线程,称之为定时器线程
  3. 添加新回调后,将其添加到排序列表中
  4. 定时器线程可以初始化为等待排序列表或头中的最少时间。在添加新回调时重新初始化它。会有一些数学和条件需要处理
  5. 当定时器线程完成休眠时,它会删除并查看列表的头部,并在新线程中执行函数指针。计时器线程在列表的新头上用睡眠时间重新初始化。

    main() {
    //spawn a timer thread with pthread create 
    callfunctiontimed(25, test); 
    callfunctiontimed(35, show);
    callfunctiontimed(4,  print);
    }
    callfunctionTImed(int time, (func*)function, void*data) //
    {
    //add information to sorted list of timer and callbacks
    //re-initialize sleep_time for timer thread if needed. 
    return. 
    }
    timerThread() {
    while(1){
    sleep(sleep_time);
    //look at head of timer list, remove it, call function in a new thread   
    //adjust sleep time as per new head     
    }
    }
    

希望这能让我明白我的意思,尽管这并不完美,而且有几个问题。

在windows中,您有SetTimer-http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

样本代码:

#define STRICT 1 
#include <windows.h>
#include <iostream.h>
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) 
{


cout << "CALLBACK " << dwTime << 'n';
cout.flush();
}
int main(int argc, char *argv[], char *envp[]) 
{
int Counter=0;
MSG Msg;
UINT TimerId = SetTimer(NULL, 0, 2000, &TimerProc); //2000 milliseconds
cout << "TimerId: " << TimerId << 'n';
if (!TimerId)
return 16;
while (GetMessage(&Msg, NULL, 0, 0)) 
{
++Counter;
if (Msg.message == WM_TIMER)
cout << "Counter: " << Counter << "; timer messagen";
else
cout << "Counter: " << Counter << "; message: " << Msg.message << 'n';
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}

最新更新