Linux 不使用信号回调的周期性 C 定时器

Linux periodic C timers without using signal callback

要求很简单 - 实现一个 C 周期性计时器,它可以每隔 x 秒触发一次,并且每次计时器到期时都应调用计时器回调函数。似乎是一个足够简单的问题,我已经浏览了网络,但我找到了涉及 FD 和轮询的示例,或者计时器回调是使用 SIGNAL 处理程序实现的。我想避免两者。能否分享一些代码示例

https://man7.org/linux/man-pages/man2/timer_create.2.html - 使用信号,在我的过程中我不感兴趣,可能还有其他原因可以调用这个信号,我如何在 SIG 处理程序中区分这个信号是我的计时器而不是其他事件?

how can I differentiate in the SIG-handler, that this signal is for my timer and not other events ?

查看 sigevent(7) man page linked from timer_create(2). One of the members of the struct sigevent that you pass to timer_create is union sigval sigev_value. This union isn't defined in the man page, but POSIX 解释它只是

union sigval {
    int    sival_int;  // integer signal value
    void*  sival_ptr;  // pointer signal value
};

无论您在此处设置什么,都将作为其 siginfo_t * 第二个参数的 si_value 成员传递给您的信号处理程序,前提是您在调用 sigaction 时使用 SA_SIGINFO。所以你只需要在这里使用不同的值,因为你设置定时器对应不同的回调。您可以将 sival_int 用作您自己选择的整数 ID,该 ID 可将此特定计时器从所有其他计时器中唯一标识出来,或者将 sival_ptr 用作指向函数的指针或一些更详细的数据结构,告诉您如何处理计时器滴答声。然后你的信号处理程序只需要检查这个参数并分派给它指定的回调。

您还可以考虑 timer_createSIGEV_THREAD 模式,它使用处理程序触发新线程而不是发出信号。因此,如果您希望在自己的线程中回调 运行,那可能是一种更简单的方法,因为您不需要信号处理程序充当调度程序。

但是如果您不想要额外的线程,我认为没有任何方法可以避免使用信号。它们是 Unix 为 运行 异步代码提供的唯一机制。

请注意在信号处理程序中可以执行的操作的许多限制;特别是,实际上整个标准 C 库都是禁止访问的。因此,您的“异步”回调可能无法做很多事情,只能设置一个标志来告诉您的主事件循环在稍后的某个时间完成真正的工作。所以你可能不会从同步 poll 类型的模型中获得太多。