【问题标题】:timer_create how to stop recursive thread function invocation after first timer expiry?timer_create 如何在第一个计时器到期后停止递归线程函数调用?
【发布时间】:2011-07-27 16:22:33
【问题描述】:

我使用简单的“timer_create”创建了一个计时器。计时器是使用 SIGEV_THREAD 创建的。也就是当定时器到期时,会调用定时器线程函数。

timer_create 是如何工作的,假设假设:expiry=3 secs 和timer interval is 1 ns,那么计时器会每 1 ns 计时一次,直到到期。一旦计时器到期,从该实例开始,它会在每 1 ns(计时器间隔)后继续触发计时器线程函数。并继续每次点击创建一个线程,直到计时器被删除。

我不希望这种情况发生,我希望一旦计时器到期,它应该只触发一次线程函数。

我怎样才能做到这一点?我们可以在 timer_create 中添加任何选项吗?如果没有其他计时器 API?

提前非常感谢

【问题讨论】:

    标签: c linux timer


    【解决方案1】:

    只需将计时器间隔设置为 0 并到期即可。您的计时器将过期一次(并创建并运行线程),然后保持解除状态。

    【讨论】:

    • 你确定吗?计时器仅启动和武装一次。一旦开始,我们不能重新设置时间,否则会失败。
    • 计时器的工作方式是到期倒计时到零,然后计时器触发,然后将间隔复制到到期,整个事情重新开始。所以,做一个一次性的时间,这是我对你想要什么的理解,将到期编程为你需要的并将间隔设置为零。计时器将从到期计数到零,将触发一次然后被禁用。此时,您应该能够使用 settime 再次对其进行重新编程。那是你想要的吗?
    【解决方案2】:

    我认为这是 POSIX 计时器的 glibc 实现中的一个实现缺陷。对于实时使用至关重要的 timer_getoverrun 函数肯定无法在 glibc 实现中工作,因为它从内核返回“当前”到期的溢出计数,但是当多个到期事件并行运行时,“当前”没有意义。资源耗尽和过期事件丢失也存在严重问题,这使得实现无法用于实时目的。例如在nptl/sysdeps/unix/sysv/linux/timer_routines.c:

    struct thread_start_data *td = malloc (sizeof (*td));
    
    /* There is not much we can do if the allocation fails.  */
    ...
    

    sigevent 的 Linux 手册页中,您可以看到 SIGEV_THREAD

    这里的实现可能性之一是每个计时器通知都可能导致创建一个新线程,或者创建一个线程来接收所有通知。

    后者是唯一可以提供正确实时语义的选择,但出于某种原因,glibc 没有采用这种选择。

    这是一个可能的解决方法:

    选择一个实时信号,在创建任何线程之前阻止该信号,并设置您的计时器以将该信号与SIGEV_SIGNAL 一起使用。现在,创建一个线程来处理您的计时器,并在sigwaitinfo 上循环,然后在每次返回时调用您的处理程序函数。这实际上是 glibc 应该使用的SIGEV_THREAD 的一种可能实现(也是最正确的实现)。

    另一种可能性:在 POSIX 中只有一个同步相关、非系统调用调用、异步信号安全函数:sem_post。因此,可以使信号处理程序(与从sigwaitinfo 获取信号相反)与另一个线程同步以传递计时器事件。但是我还没有弄清楚细节,看起来可能仍然很难或不可能。

    【讨论】:

    • 这是 glibc 的一个严重的实现缺陷,真的。您的解决方案看起来不错,但我们不能使用信号。这是工具和设计要求。您还有其他选择吗?难道我们不能在设置定时器的时候放任何选项,我们可以指定线程数吗?
    • 不,没有这样的选项。另一种解决方法是忘记计时器并简单地创建一个重复休眠的线程,直到给定的 absolute 时间(您需要使用绝对时间而不是相对时间以避免错误累积),并读取当前时间以手动计数溢出。 clock_nanosleep 有这个功能。使用 1ns 计时器,尽管您根本不会睡觉,并且每次您设法处理的到期时间至少有 5000-10000 次溢出。
    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多