【问题标题】:How to insulate a job/thread from crashes如何使作业/线程与崩溃隔离
【发布时间】:2011-04-03 05:56:43
【问题描述】:

我正在开发一个库,我将各种任务交给一些第三方库,这些库执行一些相对粗略或危险的特定于平台的工作。 (具体来说,我正在编写一个数学函数解析器,它调用 JIT 编译器,如 LLVM 或 libjit,以构建机器代码。)在实践中,这些第三方库有崩溃的趋势(部分原因是我的错,当然,但我仍然想要一些保险)。

然后,我希望能够非常优雅地处理一项可怕的工作——SIGSEGV、SIGILL 等——而不会关闭我的其余代码(或调用我的库的用户的代码)职能)。需要明确的是,我不关心该特定工作是否可以继续(我不会尝试修复崩溃条件),我也不真正关心此类崩溃后对象的状态(我会丢弃如果发生崩溃,请立即使用它们)。我只想能够检测到发生了崩溃,阻止崩溃退出整个进程,停止调用任何崩溃的内容,并恢复执行。

(对于更多的上下文,此刻的代码是一个 for 循环,测试每个可用的 JIT 编译器。其中一些编译器可能会崩溃。如果他们这样做,我只想执行 continue; 并获取继续测试另一个编译器。)

目前,我有一个基于signal() 的实现非常糟糕地失败了;当然,longjmp() 超出信号处理程序是未定义的行为,并且信号处理程序很可能以exit()terminate() 结尾。只是将代码扔到另一个线程中本身并没有帮助,至少到目前为止我测试它的方式是这样。我也无法找到使用 C++ 异常来完成这项工作的方法。

那么,使一组特定指令/线程/作业免受崩溃影响的最佳方法是什么?

【问题讨论】:

    标签: c++ multithreading crash signals setjmp


    【解决方案1】:

    产生一个新进程。

    【讨论】:

    • 这是唯一的方法。线程可能会破坏进程中的任何地方的内存,因此在 SEGV 之后,您不能保证您的内存不受影响。
    • 感谢您的提醒。几乎可以肯定这里的正确答案。我要去阅读关于 fork() 和公司的内容。
    【解决方案2】:

    当作业成功时你会收集什么输出?

    我问是因为如果输出是低带宽,我会很想在自己的进程中运行每个作业。

    您启动的这些崩溃作业中的每一个都极有可能损坏进程中其他地方使用的内存。

    进程提供最好的保护。

    【讨论】:

      【解决方案3】:

      进程提供了最好的保护,但您可能无法做到这一点。

      如果您的线程的入口点是您编写的函数(例如,Windows 世界中的ThreadProc),那么您可以将它们包装在try{...}catch(...) 块中。如果您想传达发生了异常的信息,则可以将特定的错误代码传达回主线程或使用其他一些机制。如果您不仅要记录发生的异常,还要记录该异常是什么,那么您需要捕获特定的异常类型并从中提取诊断信息,以便与主线程进行通信。阿拉:

      int my_tempermental_thread()
      {
        try
        {
          // ... magic happens ...
          return 0;
        }
        catch( const std::exception& ex )
        {
          // ... or maybe it doesn't ...
          string reason = ex.what();
          tell_main_thread_what_went_wong(reason);
          return 1;
        }
        catch( ... )
        {
          // ... definitely not magical happenings here ...
          tell_main_thread_what_went_wrong("uh, something bad and undefined");
          return 2;
        }
      }
      

      请注意,如果您采用这种方式,则可能会在发生异常时冒充主机进程的风险。你说你不是在试图纠正问题,但是你怎么知道恶性线程没有吃掉你的堆栈? Catch-and-ignore 是一种创建可怕的令人困惑的错误的好方法。

      【讨论】:

        【解决方案4】:

        在 Windows 上,您可以在调用不受信任的代码时使用VirtualProtect(YourMemory, PAGE_READONLY)。任何修改此内存的尝试都会导致结构化异常。您可以安全地捕捉到这一点并继续执行。但是,该库分配的内存当然会泄漏,其他资源也是如此。 Linux 等效项是 mprotect(YorMemory, PROT_READ),它会导致 SEGV。

        【讨论】:

          猜你喜欢
          • 2013-02-01
          • 2018-08-12
          • 2012-10-28
          • 1970-01-01
          • 2016-10-26
          • 2021-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多