【问题标题】:SIGALRM Timeout -- How does it affect existing operations?SIGALRM 超时——它如何影响现有操作?
【发布时间】:2011-03-15 13:45:41
【问题描述】:

我目前正在使用select() 作为计时器。我有一个循环内发生的网络接收操作,每隔几秒钟就需要进行一次处理操作。

因此,select() 语句的超时时间不断变化——随着时间的推移减少到零,然后在 3 处重新开始。

rv = select(selectmonitor+1, &readnet, NULL, NULL, &helper.timeout());

随着网络上的事情进入,该语句被重复并且由 helper.timeout() 传递给它的值减少。最终,该值要么为零,要么系统超时,这将导致处理函数执行。但是,我注意到这非常耗费资源——必须不断计算 helper.timeout() 的值。当我尝试每秒接收几千个数据包时,完成此操作所需的时间会导致数据包丢失。

我的新想法是使用SIGALRM 来解决这个问题。这将允许我设置一次计时器,然后在它关闭时做出反应。但是,我对它将如何影响我的程序感到困惑。当 SIGALRM “关闭”时,它将运行我指定的函数。但是,它将如何中断我现有的代码?一旦函数完成,我现有的代码(在while 语句中)将如何恢复?

另外,设置 SIGALRM 信号来调用类中的函数似乎是不可能的?它是否正确?我想我可以调用一个函数,该函数又可以调用一个类中的一个函数..

感谢您提前提供的任何帮助。

【问题讨论】:

    标签: c++ select performance timeout signals


    【解决方案1】:

    使用您的 SIGALRM 处理程序设置标志变量。

    使用sigaction 而不是signal 来设置您的信号处理程序。不要设置 SA_RESTART 标志。使用 SA_RESTART not 设置,您的 select 语句将被信号中断。您的选择将返回 -1 并且 errno 将是 EINTR。

    由于信号可能在您的其他代码执行时发生,您也需要检查标志变量,可能就在进入选择之前。

    我刚刚被提醒,如果这种模式发生在检查标志之后和进入选择之前,这种模式可能会导致丢失信号。

    为避免这种情况,您需要在进入 while 循环之前使用sigprocmask 阻止 SIGALRM 信号。然后你使用pselect 而不是select。通过给pselect 一个未屏蔽 SIGALRM 的信号掩码,信号最终将始终在选择期间中断,而不是在任何其他时间发生。

    【讨论】:

    • 补充一点,使用信号(alarm() 所做的)可能会导致许多其他系统调用“失败”,并且如果系统调用时警报响起,也将 errno 设置为 EINTR执行 - 应该注意
    • @Zan -- 你的回答有点令人困惑:“不要使用 SA_RESTART 标志,你的 select 语句会被信号打断”。你是说如果我不使用 SA_RESTART 标志,我的 select 语句就会被中断?还是那两个不同的东西。
    • @nos -- 你是否建议以前使用 select() 安排超时的方法更好?
    • @BSchlinker:如果您指定 SA_RESTART,那么大多数系统调用将永远不会返回 -1 和 EINTR,因为它们会自动重新启动。
    • @BSchlinker ,不是真的 - 但我是说信号处理通常很麻烦 - 如果您需要“更好”的东西,我建议您查看 timerfd_create 的联机帮助页,如果可以的话linux特定的东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 2013-09-30
    • 2013-09-12
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    相关资源
    最近更新 更多