从信号处理程序访问共享内存

时间:2012-09-15 21:27:17

标签: multithreading concurrency multiprocessing deadlock semaphore

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

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

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

那么实现这一目标的最佳方式是什么?我的子进程都注册了相同的信号处理程序,用于处理类型的信号,让我们说1.因此,无论何时收到该特定信号,它们的信号处理程序都会尝试递增计数器。

如何实现这一目标?

1 个答案:

答案 0 :(得分:0)

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

(同样的自我死锁问题隐藏在所有类型的公共调用中,例如malloc。这就是为什么有一个非常短的库函数列表,保证“信号安全”。)

我认为有几种方法可以解决这个问题:

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