【问题标题】:C/C++ SIGINT received between condition and blocking call在条件和阻塞调用之间收到 C/C++ SIGINT
【发布时间】:2019-08-09 14:20:18
【问题描述】:

线程 A 在循环中执行一个阻塞调用,直到线程 B 发出信号继续执行其余部分。

我尝试了信号处理程序的经典方法,它会更改条件变量,因此我可以在下一次调用开始之前测试条件。

现在问题出现在这种情况下,当信号在条件检查之后到达,但在阻塞调用之前。

问题的简短伪代码示例:

while(!isInterrupted){
  raise(SIGINT)
  block()
}  

假设我无法访问或更改阻塞代码的实现,并且阻塞调用不提供内部超时功能,信号处理程序可以将其设置为最小值,那么 C 和 C++ 的正确方法是什么?处理这个?

信号被用作阻塞调用,只能通过接收 SIGINT 来唤醒。

提前感谢您的帮助。

【问题讨论】:

  • 你需要一个原子的“解锁并等待”函数。
  • 您可能需要考虑长跳出信号处理程序。这可能是一个好主意,也可能不是一个好主意,具体取决于阻塞调用的性质。
  • @user58697 谢谢,没想到。你说的对。在某些情况下,包括这个,这是最不臃肿的方式。祝你有美好的一天!

标签: c++ c signals


【解决方案1】:

如果您可以像我使用 https://github.com/pskocik/musl 那样修改您的 libc 的调用程序集,那么您可以通过让您的信号处理程序调用一个特殊函数(在修改后的 libc 中提供)来消除这个 time-of-check to time-of-use problem,这将打破如果在您的代码在检查后处于函数调用包装器中但尚未处于内核模式时收到信号,则系统调用(在内核模式下,阻塞调用自然会被信号传递自然地破坏)。

如果无法访问您的 libc(/您纯粹在 POSIX 之上构建),我相信您能做的最好的事情就是基于协议的解决方案:

  • 设置信号接收器确认信号接收的机制
  • 重复发送信号代码(最好是在休眠状态下),直到收到确认

但这可能不是最容易设置的(本质上,您会在一定程度上与 POSIX 作斗争)。如果您负担得起,在新线程中执行阻塞操作应该更简单,并且pthread_cancelpthread_kill 不同,应该能够可靠地在目标中引发响应(在这种情况下,完全线程取消),不像pthread_kill.

使用单独线程的缺点是它会占用更多资源。

【讨论】:

    【解决方案2】:

    停止使用阻塞调用,然后切换到实际的同步原语。

    【讨论】:

    • 感谢您的努力,但这根本没有帮助。有时您无法更改所提供的内容,而必须充分利用它。
    • 现代我们使用非阻塞套接字是有原因的。您只是使用了错误的工具来完成这项工作。努力改变所提供的内容。
    【解决方案3】:

    请查看互斥锁和条件变量。

    【讨论】:

    • 抱歉,我不明白这些会有什么帮助。如果我在检查条件之前通知条件变量,它仍然可以工作。如果我在阻塞期间通知它,我仍然需要信号,因为条件变量无法唤醒阻塞调用。如果在这两者之间收到通知,线程仍然会在之后正常恢复并启动阻塞调用,而无法唤醒它。我希望我在这里有一个疏忽。
    猜你喜欢
    • 2011-03-02
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多