Multithreading 如何使用pthreads在*nix系统上实现异步计时器
我有两个问题: Q1我可以在单线程应用程序中实现异步计时器吗?也就是说,我想要这样的功能Multithreading 如何使用pthreads在*nix系统上实现异步计时器,multithreading,unix,pthreads,Multithreading,Unix,Pthreads,我有两个问题: Q1我可以在单线程应用程序中实现异步计时器吗?也就是说,我想要这样的功能 .... Timer mytimer(5,timeOutHandler) .... //this thread is doing some other task ... and after 5 seconds, the timeOutHandler function is invoked. 就我所知,单线程应用程序无法做到这一点。如果我错了,请纠正我。我不知道是否可以使用select作为解复用器,
....
Timer mytimer(5,timeOutHandler)
.... //this thread is doing some other task
...
and after 5 seconds, the timeOutHandler function is invoked.
就我所知,单线程应用程序无法做到这一点。如果我错了,请纠正我。我不知道是否可以使用select作为解复用器,但即使可以使用select,事件循环也需要一个线程?不是吗
我还想知道是否可以使用select实现timernot timeout。
Select仅等待一组文件描述符,但我希望有一个计时器列表,按其过期超时的升序排列,并希望Select告诉我第一个计时器何时过期,依此类推。因此,问题可以归结为异步计时器是否可以使用select/poll或其他事件解复用器实现
问题2现在让我们来看我的第二个问题。这是我的主要问题。
现在我使用一个专用线程来检查超时,也就是说,我有一个最小的timersexpiry时间堆,这个线程一直休眠到第一个计时器过期,然后调用回调。
i、 e代码看起来像这样
锁定互斥锁
检查第一个计时器的时间
condition timed wait等待该时间,如果其他线程插入了到期时间小于第一个计时器condition wait的计时器,则唤醒该线程以解锁锁。
在条件等待结束后,我们拥有锁。因此,解锁它,从堆中移除计时器并调用回调函数。
转到1
我想要这种异步计时器的时间复杂度。据我所见
插入是lgn
到期日为lgn
取消
:这就是让我头晕的原因。问题是,我有一个最小的计时器堆,根据它们的时间,当我插入计时器时,我会得到一个唯一的id。因此,当我需要取消计时器时,我需要提供此计时器id,在堆中搜索此计时器id将在最坏的情况下发生
我错了吗
可以在Olg n中取消吗
请注意一些多线程问题。一旦我得到一些回复,我会详细解释我上一句话的意思。如果你是windows应用程序,你可以在将来的某个时候触发WM_定时器消息发送给你,即使你的应用程序是单线程的,它也会起作用。但是,计时的准确性不会太高 如果你的应用程序像游戏一样在一个恒定的循环中运行,以60Hz的频率渲染,你只需在循环的每一次中检查是否需要调用触发的事件
如果你希望你的应用程序基本上被中断,你的函数被调用,然后执行返回到原来的位置,那么你可能会运气不佳。如果你使用的是C,System.Timers.Timer会做你想做的事情。指定计时器到期时调用的事件处理程序方法,该方法可以位于从中调用计时器的类中。请注意,当计时器调用事件处理程序时,它将在一个单独的线程上执行,如果您正在更新用户界面,或使用其SynchronizationObject属性在UI线程上运行它,则需要考虑到这一点。使用单个线程实现计时器肯定是可能的,而且通常更可取,如果我们可以假设线程将花费大部分时间在select中阻塞 您可以使用signal和SIGALRM来实现POSIX下的功能,但我建议您不要使用Unix信号,因为Unix信号是丑陋的黑客,当signal回调函数运行时,您在它内部安全地做的事情很少,因为它与您的应用程序线程异步运行 您关于使用select的超时来实现计时器功能的想法是很好的——这是一种非常常见的技术,而且效果很好。基本上,您保留了一个按时间戳排序的挂起/即将发生的事件列表,在调用select之前,您从列表中的第一个时间戳中减去当前时间,并将该时间增量作为超时值传递给select。注意:如果时间增量为负数,则传入零作为超时值!选择返回时,将当前时间与列表中第一项的时间进行比较;如果当前时间大于或等于事件时间,请处理计时器事件,从列表开头弹出第一项,然后重复
至于效率,big-O时间将完全取决于用于存储有序计时器列表的数据结构。如果使用优先级队列或类似的有序树类型结构,则所有操作都可以使用Olog N次。您甚至可以更进一步,将事件列表存储在事件ID上的哈希表和按时间戳排序的链表中,这可以为所有操作提供O1次。不过,Olog N可能已经足够有效了,除非您计划一次挂起大量事件。您在哪个平台上写这篇文章?例如,Windows有一些API调用,允许我们使用单线程应用程序
man pthread_cond_timedwait
man pthread_cond_signal
我有一个计时器。或者你正在尝试编写自己的操作系统?大家好,我在*nix系统上工作,即任何兼容posix的linux、solaris和其他Unice系统。我正在使用pthreads。您在这里介绍的第二个选项实际上是可能的,只是实现起来非常痛苦: