【问题标题】:How to implement Javascript's setTimeout() function in C (not C++)如何在 C(不是 C++)中实现 Javascript 的 setTimeout() 函数
【发布时间】:2020-02-23 16:39:26
【问题描述】:

标题说明了一切。 我已经看到了 C++ 中的解决方案。例如,this one 和一些(也是 C++)相当古老的。 我愿意使用 glib 或任何其他开源库。我只关心 Linux 的实现。

我遇到了 glib 的 timer functions,但它们本质上都是同步的,并不接近 setTimeout() 的作用。

我可以想到一种解决方案,即拥有一个单独的线程,该线程在一个循环中不断地检查计时器(例如 Glib 提供的计时器)是否已过期,然后触发相应的函数。当然,这样效率会低得离谱。

我也遇到了这个here,它建议使用alarm(2)。它可以使用,但粒度仅以秒为单位。

编辑:唉,alarm() 取消任何以前设置的 alarm()

【问题讨论】:

  • 看看闹钟和设置定时器功能。警报会生成信号,因此您需要一个信号处理程序。
  • 我添加了linux 标签,因为你说这是你关心的操作系统,而且这个问题在标准 C 中没有答案。
  • 请注意,如果您从基于事件的单线程应用程序架构转向多线程应用程序,请为痛苦的世界做好准备。我会寻找“C 事件库”而不是类似这样的线程。
  • @asinix 通常在 Linux 中,事件循环围绕select(或等效的)系统调用进行编程,超时设置为下一个计时器事件。不需要中断定时器机制或信号。可以有任意数量的计时器。
  • @hyde 就是这样!!非常感谢。现在我明白你为什么要谈论关于定时器的事件循环了!当然是一个优雅的解决方案。

标签: c linux asynchronous settimeout glib


【解决方案1】:

您提到您的流程中需要多个计时器,因此您可能需要 POSIX timer_* 系列函数(timer_createtimer_settime 等)。它们具有纳秒级粒度。您可以为计时器到期时指定一些不同的操作:引发信号,或从单独的线程调用函数。您必须与-lrt 链接才能使用这些功能。

还有timerfd_create,它允许您通过使用pollselect 或它们的亲戚来检测文件变得可读的计时器到期。

【讨论】:

  • 我正在经历它,它似乎正是我正在寻找的东西(还有更多!)。
  • 来自 sigevent 的手册页:“..SIGEV_THREAD ...这里的实现可能性之一是每个计时器通知都可能导致创建一个新线程,或者创建一个线程来接收所有通知..” 为每个通知创建一个线程至少可以说是矫枉过正。有没有办法让“创建一个线程来接收所有通知”?
  • @asinix:从 glibc 源代码看,后者是它实际所做的。它创建了一个辅助线程,除了坐下来等待信号之外什么都不做。然后它使用SIGEV_THREAD_ID 来确保定时器信号进入帮助线程,当你的定时器关闭时,它会调用你的函数。
  • 这条消息只是意味着 gdb 正试图向您显示发生崩溃的源代码行,但它在 glibc 代码中并且它不知道在哪里可以找到 glibc 源代码。您可以将源安装在某处并在 gdb 中使用dir 命令告诉它它们在哪里,这可能有助于调试,但它们的缺失并不是导致崩溃的原因。您可能应该使用完整的测试用例提出一个单独的问题。
  • 但这要么意味着您错误地调用了timer_create(请仔细阅读其手册页),或者 glibc 中存在错误。通过Jeff Atwood's First Rule,您应该假设第一种情况,直到您可以证明不是...
【解决方案2】:

如果您想使用 GLib 及其超时源(g_timeout_add()g_timeout_add_seconds() 等),那么您需要运行 GLib main loop (GMainLoop) 并在主循环回调。如果您的应用程序还没有以事件驱动的风格编写,这将是一个相当大的变化,但无论如何轮询套接字或运行 UI 都是必需的。

有一个如何在应用程序here 中使用超时源的示例。

请注意,GLib 的计时器 API (g_timer_*()) 不是用于在特定超时后运行回调,而是用于计时某件事需要多长时间(如秒表)。在这里不相关。

【讨论】:

  • 我通常更喜欢使用基本的 Linux 系统调用并避免使用其他库,除非绝对需要,因为我不打算将我的代码移植到任何其他平台。我已经为每个线程拥有了自己的事件循环,并且仅仅为了这个要求,引入 GLib 主循环将是一种过度杀戮。 Nate 建议的解决方案效果很好。但是,我会研究您建议的 Glib 函数。
  • 当然,GLib 只是一种解决方案——不过,我认为它值得在答案中进行解释,因为问题被标记为 glib 并且您在问题中明确提到了它的计时器功能。 :)
  • 对我来说,每一个解释都具有教育意义,因为我不是这方面的专家。我发现很多解决方案隐藏在 GLib 的某个地方,所以我标记了它,以防万一没有其他简单的解决方案。
猜你喜欢
  • 1970-01-01
  • 2021-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2012-11-16
相关资源
最近更新 更多