【问题标题】:Reading shared data inside a signal handler在信号处理程序中读取共享数据
【发布时间】:2012-01-19 12:04:29
【问题描述】:

我需要在信号处理程序(SIGSEGV 信号处理程序,据我所知是每个线程基础)中读取二叉搜索树 (BST)。 BST 可以被应用程序中的其他线程修改。

现在,由于信号处理程序不能使用信号量、互斥锁等,因此无法访问共享数据,我该如何解决这个问题?请注意,我的应用程序是多线程的,并且在多核系统上运行。

【问题讨论】:

  • 我会非常非常努力地想办法在信号处理程序中不读取共享数据。
  • 为了强调@dbeer 的观点,在信号处理程序中,您通常不应该做任何会阻塞或引发其他信号的事情,或者任何冗长的操作。信号处理程序应该小、快、短。
  • 也许我遗漏了一些东西,但如果你的程序的线程只访问共享内存(没有其他中断和异常),你为什么不能使用信号量(是否它的好风格是不同的题)?如果一个线程访问临界区,阻塞它,被另一个线程休眠,信号量仍然为另一个线程锁定,最终你的初始线程将被安排再次访问它。抛开性能原因不谈,我认为既没有数据损坏的危险,也没有导致系统停滞。
  • 从理论上讲,在我看来这没问题。例如,内核本身保护仅由异常访问的关键区域,有时仅使用信号量 - 在 UP 和 MP 体系结构中。但是,我对用户空间中的这些问题并没有非常实际的经验,并且可能会忽略一些东西。正如我上面所概述的,我只是不明白在你的情况下它会如何导致问题。
  • 在信号处理程序中访问共享数据的危险很容易显示:线程 A 锁定共享数据 X,当它持有锁时它处理一个信号,调用信号处理程序,它试图锁定数据 X. 死锁!

标签: c linux mutex signals signal-handling


【解决方案1】:

您不应从信号处理程序访问共享数据。您可以在以下文章中找到有关信号的更多信息:

Linux Signals for the Application Programmer

The Linux Signals Handling Model

All about Linux signals

目前看来,在 linux 中处理信号最安全的方法是 signalfd。

【讨论】:

    【解决方案2】:

    我可以看到两个非常干净的解决方案:

    1. Linux 专用:创建专用线程处理信号。使用signalfd() 捕获信号。这样,您将在常规线程中处理信号,而不是任何受限的处理程序。
    2. 可移植:还使用一个专用线程,该线程在收到信号之前一直处于休眠状态。您可以使用管道创建一对文件描述符。线程可以从第一个描述符中读取(2),并且在信号处理程序中,您可以将(2)写入第二个描述符。根据POSIX,在信号处理程序中使用 write() 是合法的。当线程从管道中读取内容时,它知道它必须执行一些操作。

    【讨论】:

      【解决方案3】:

      假设 SH 不能直接访问共享数据,那么也许您可以间接访问:

      1. 有一些全局变量,只有信号处理程序可以写入,但可以从其他地方读取(即使只能在同一个线程中)。
      2. SH 在调用时设置标志
      3. 线程不在修改 BST 的过程中轮询此标志;当找到它设置时,它们会执行原始信号所需的处理(使用任何必要的同步),然后发出不同的信号(如 SIGUSR1)以指示处理已完成
      4. 该信号的 SH 重置标志

      如果您担心 SIGSEGV 重叠,请在混合中添加一个计数器以跟踪。 (嘿!您刚刚构建了自己的信号量!)

      这里的薄弱环节显然是轮询,但它是一个开始。

      【讨论】:

      • 我的想法完全一样:-p!但是当信号发生时线程正在修改 BST 会发生什么。这一点有点令人担忧。
      • 我认为这不是问题:信号会被捕获,设置标志并返回;线程将继续修改 BST,并且在完成修改之前不会尝试“处理”信号。假设这些修改是原子的,这似乎是一个合理的结果。
      【解决方案4】:

      您可以考虑使用mmap-ing 一个fuse 文件系统(在用户空间中)。

      其实你会更高兴Gnu Hurd支持external pagers

      也许你在信号处理程序中读取二叉搜索树的技巧通常可以在实践中工作,不可移植并且以依赖于内核版本的方式。也许使用低级不可移植技巧(例如futexesatomic gcc builtins)对访问进行序列化可能会起作用。阅读 NPTL 的(特定于机器的)源代码,即当前的 Linux pthread 例程应该会有所帮助。

      这可能是pthread_mutex_lock 等实际上可以在 Linux 信号处理程序内部使用的情况...(因为它可能只执行 futex 和原子指令)。

      【讨论】:

        猜你喜欢
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多