2009-08-03 88 views
3

我们有一个处理事件定时器的API。这个API说它使用OS回调来处理定时事件(显然使用select())。Unix中的C++定时器

的API权利要求执行的该顺序,以及: 可读事件 可写事件 计时器事件

这通过创建指向一个定时器对象,但传递创建功能的功能回调:

沿着这些线:

Timer* theTimer = Timer::Event::create(timeInterval,&Thisclass::FunctionName); 

我想知道这是如何工作的?
操作系统正在处理定时器本身,并且当它看到它被触发时它如何实际调用回调?回调是否在单独的执行线程中运行?

当我在回调函数(Thisclass :: FunctionName)中放置一个pthread_self()调用时,它看起来与自己创建Timer的线程具有相同的线程ID! (由此非常困惑)

另外:以上的优先级列表是什么意思?什么是可写事件vs可读事件vs计时器事件?

也赞赏在这种情况下使用select()的任何解释。

谢谢!

+2

链接到相关API的文档会很有帮助等待所有计时器。如果它是一些内部的东西,请阅读源代码;有许多方法可以实施。 – bdonlan 2009-08-03 15:45:17

回答

2

这看起来像一个简单的包装select(2)。这个类保存了一个回调列表,我猜是分开读取,写入和计时器到期的。然后有一个像调用dispatchwaitwait的调用,将给定的文件描述符打包成集合,计算最小超时值,并用这些参数调用select。当select返回时,包装器可能会先读取set,调用read回调,然后写入set,然后查看是否有任何定时器已过期并调用这些回调。这一切都可能发生在同一个线程上,或者在单独的线程上发生,具体取决于包装器的实现。

您应该阅读selectpoll - 它们非常方便。 通用术语是IO解复用

1

根据猜测,对create()的调用将函数指针存储在某处。然后,当计时器关闭时,它会调用您通过该指针指定的函数。但是,由于这不是标准C++函数,所以您应该真正阅读文档或查看源代码以确定。

关于您的其他问题,我没有看到提及优先级列表,select()是一种通用事件多路复用器。

2

可读事件意味着数据可用于在不阻塞的情况下读取特定文件描述符,而可写事件意味着您可以在不阻塞的情况下写入特定文件描述符。这些通常用于插座和管道。有关这些的详细信息,请参阅select()手册页。

计时器事件意味着先前创建的计时器已过期。如果库使用的是select()poll(),库本身必须跟踪定时器,因为这些函数接受单个超时。库必须计算直到第一个定时器到期的剩余时间,并将其用于超时参数。另一种方法是使用timer_create()或更早的变体(如setitimer()alarm())通过信号接收通知。

您可以使用类似strace(Linux)或truss(Solaris)的工具来确定在OS层使用哪种机制。这些工具跟踪程序正在进行的实际系统调用。

1

很可能有一个框架与典型的主循环一起工作,主循环的驱动力是select调用。

select允许您等待filedescriptor变为可读或可写(或filedeescriptor上的“异常”)或发生超时。我猜这个库也允许你为异步IO注册回调,如果它是一个GUI库,它将通过unix上的一个文件描述符得到低级的基本GUI事件。

要在这样的循环中实现定时器回调,您只需保留定时器的优先级队列并在选择超时或filedescriptor事件上处理它们。

优先级意味着它在计时器之前处理文件I/O,这本身需要时间,可能导致GUI更新,最终导致GUI事件处理程序正在运行,或者其他任务花费时间服务I/O。

图书馆或多或少做

for(;;) { 
    timeout = calculate_min_timeout(); 
    ret = select(...,timeout); //wait for a timeout event or filedescriptor events 
    if(ret > 0) { 
    process_readable_descriptors(); 
    process_writable_descriptors(); 
    } 
    process_timer_queue(); //scan through a timer priority queue and invoke callbacks 
} 
0

因为事实计时器回调内部线程ID是一样的创造者线程我认为这是使用信号来实现莫名其妙。

当一个信号发送到线程的状态被保存并且调用信号处理程序然后调用事件回调。 所以处理程序在创建者线程中被调用,该线程被中断,直到信号处理程序返回。

也许另一个线程使用select(),如果计时器到期就发出信号至到期定时器在创建线程。