C语言定时器库

9
我正在寻找一个用 C 写的开源计时器库,该库应具有计时器回调函数等功能。
在搜索时,我看到了 POSIX 计时器或 setitimer(),它们使用基于信号的方法,这可能会导致多线程代码中出现问题。
假设我在线程化的代码中使用 POSIX 计时器,则信号将无法到达正确的位置。如果我在进程中使用多个计时器,则每个计时器都应使用不同的信号。是否有其他选择?

通常解释为什么会被投票降低或关闭是有帮助的。 - i_am_jorf
这篇文章可能会引发争议、争论、投票或长时间的讨论,因此它正在接近被关闭。请先做一些研究,尝试使用一个或多个候选方案,如果遇到问题可以提出询问。例如,“我能在多线程代码中使用POSIX setitimer吗?”这是一个好问题。 - Useless
我回答了关于在线程化代码中使用POSIX定时器的问题。这是可行的,我展示了文档中相关的部分。 - Chimera
一个程序可以使用timer_create()创建多个间隔定时器。请参考我的回答。 - Chimera
我最终使用了libdispatch,这个库在macOS上可用,并且已经被移植到多个其他系统。 - Albin Stigo
3个回答

11

由于您正在运行Linux,我建议使用内置的POSIX定时器API。

int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);

这里有一份关于如何使用 POSIX 定时器的文档,它提供了对回调函数的支持。
关于一个进程中多个定时器的问题,文档中说:
   A program may create multiple interval timers using timer_create().

   Timers are not inherited by the child of a fork(2), and are disarmed and
   deleted during an execve(2).

   The kernel preallocates a "queued real-time signal" for each timer created
   using timer_create().  Consequently, the number of timers is limited by the
   RLIMIT_SIGPENDING resource limit (see setrlimit(2)).

请注意,可以通过使用如下所示的SIGEV_THREAD_ID设置通知,在多线程应用程序中使用POSIX计时器:
The sevp.sigev_notify field can have the following values:

       SIGEV_NONE
              Don't asynchronously notify when the timer expires.  Progress of the
              timer can be monitored using timer_gettime(2).

       SIGEV_SIGNAL
              Upon timer expiration, generate the signal sigev_signo for the process.
              See sigevent(7) for general details.  The si_code field of the
              siginfo_t structure will be set to SI_TIMER.  At any point in time, at
              most one signal is queued to the process for a given timer; see
              timer_getoverrun(2) for more details.

       SIGEV_THREAD
              Upon timer expiration, invoke sigev_notify_function as if it were the
              start function of a new thread.  See sigevent(7) for details.

       SIGEV_THREAD_ID (Linux-specific)
              As for SIGEV_SIGNAL, but the signal is targeted at the thread whose ID
              is given in sigev_notify_thread_id, which must be a thread in the same
              process as the caller.  The sigev_notify_thread_id field specifies a
              kernel thread ID, that is, the value returned by clone(2) or gettid(2).
              This flag is only intended for use by threading libraries.

如果我在线程代码中使用POSIX定时器,则信号将无法到达正确的位置。如果我在进程中使用多个定时器,则每个定时器应该使用不同的信号。还有其他替代方案吗? - m4n07
您可以使用SIGEV_THREAD_ID设置通知以使其与线程相关联。因此,计时器信号将发送到您希望它发送到的线程ID。 - Chimera
“这里有一个链接,展示了如何使用POSIX定时器来支持回调函数。” - 在哪里?我没有看到任何提到回调函数的地方。 - Mawg says reinstate Monica
1
通过 sevp 结构体的 sevp.sigev_notify 成员。 - Chimera
你能详细说明一下吗? - Mawg says reinstate Monica
请参考 SIGEV_THREAD 来查看 sevp.sigev_notify - Chimera

7

在Linux中,可以通过timerfd_create实现,它可以很好地与基于epoll的事件循环集成(从而避免了信号处理程序的限制)。


想了解timefd的分辨率精度。 - m4n07
它与timer_create完全相同,因为基础架构是相同的 - 只是通知接口不同。 - cmeerw
谢谢!这正是我需要与 epoll_wait() 一起使用的东西,但我认为我花了一个小时研究定时器和 epoll,没有注意到任何其他人提到过这一点。非常感激。 - Peter Hansen

-6

这个太简单了,可以轻松创建一个库。

例如:

#include <time.h>
int main()
{
    time_t start,end;
    double dif;
    double duration=40f; //duration of timer
    bool loop=true;
    while(loop==true)
    {
        time(&start);
        if(dif==duration)
        {
            /*callback*/
            dif=0;
        }
        //do stuff
        time(&end);
        dif+=difftime(end,start);
    }
{


简单的解决方案,但它并没有提供一个适当的回调机制。 - Chimera
让它这么做并不难。我只是抛出了这个想法。 - tsturzl
3
使用定时器回调的主要目的是避免在每次迭代中检查时间! - Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接