1

我在使用信号处理程序时遇到了这个问题。我有一个定义共享内存的父进程。它派生出两个子进程,它们具有用于某种类型信号的信号处理程序。现在,只要子进程接收到该特定信号,它们的信号处理程序就会处理该信号。

现在我需要跟踪信号处理程序处理信号的次数。我需要使用该共享内存来增加计数器的信号由任一子进程处理的次数

为此,我可能需要使用信号量。但我的问题是,每当信号由处理程序处理时,它必须检查是否正在访问共享内存,如果正在访问它不能增加计数器,那么它可能不得不阻塞。我认为我们不能阻止信号处理程序。

那么实现这一目标的最佳方法是什么。我的两个子进程都注册了相同的信号处理程序来处理类型为 1 的信号。因此,每当接收到该特定信号时,它们的两个相同的信号处理程序例程都会尝试增加计数器。

如何做到这一点?

4

1 回答 1

0

您可以在信号处理程序中阻塞,有点。我的意思是:你可以安全地阻止其他进程完成它正在做的事情。不寻常的死锁可能性是您自己的进程 - 如果进程中的特定线程已锁定互斥锁(或信号量),则内核劫持该线程来处理信号,并等待锁定:死锁。线程的主堆栈在信号处理程序完成之前不会释放锁,信号处理程序在主堆栈释放锁之前不会完成。

(同样的自死锁问题隐藏在各种常见的调用中,比如malloc. 这就是为什么有一个非常短的库函数列表可以保证“信号安全”。)

我看到了解决这个问题的几种方法:

  • 不允许信号处理程序从具有锁的线程运行。至少有三种方法可以使用pthread_sigmask
    1. 您可以在获取锁之前暂时屏蔽该线程中的信号,并在锁释放后取消屏蔽它。当然,额外的系统调用会产生一些成本,因此如果这是对性能敏感的代码,您可能希望避免这种方法。
    2. 您可以在所有线程中永久屏蔽它,并使用sigwait来自某个线程的循环来处理信号,而根本不需要传统的信号处理程序。这将使您摆脱对“信号安全”功能等的所有担忧。
    3. 您可以在该线程中永久屏蔽它,并让其他线程使用传统的信号处理程序运行,要么执行其他“实际”工作,要么只是一个sigsuspend循环。
  • 使用原子。如果这是一个简单的计数器,您可以完全避免锁定。信号处理程序从不等待主线程。主线程也没有特别的问题——也许一个比较和交换循环会运行一个额外的迭代,因为信号处理程序在两者之间运行,但这并不是一个真正的问题。不过,我不完全确定C++11 原子是否能保证在共享内存区域上正确运行。您可能需要查看平台的实现。我无法想到他们会关心其他线程与使用共享内存段的其他进程的任何原因,但我不想过度承诺。
于 2013-01-17T18:39:10.970 回答