【问题标题】:Prevent the application from crashing if one of the threads crashed如果其中一个线程崩溃,防止应用程序崩溃
【发布时间】:2021-12-08 14:42:03
【问题描述】:

有什么办法可以防止主线程崩溃?
我希望主线程在这个内存访问冲突异常发生后继续运行。

std::thread {
    []() {
        for (auto i = 0; i < 10; ++i) {
            std::cout << "Hello World from detached thread!\n";
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
        std::cout << "Boom!\n";
        *(int*)(0) = 42;
    }
}.detach();

while (true) {
    std::cout << "Hello World!\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
}

【问题讨论】:

  • 技术上这是可能的,但是您应该专注于消除访问冲突和其他内存损坏问题的可能性。
  • 因此,在一个线程(与所有其他线程共享地址空间)损坏内存后,您希望所有其他线程继续进行,就好像一切都很好,并继续使用损坏的内存?对我来说,这听起来像是灾难的秘诀。
  • 如果一个线程崩溃,它会使运行时支持库处于无效状态,它可能由于自身或其他线程造成的内存损坏而崩溃。对于非关键任务系统,我通常的建议是 - 尽快记录(如果可能)并退出程序。
  • 如果线程崩溃,Crom 只知道它带来了什么。让程序死掉并重新启动,你几乎肯定最好还是失败。
  • 处理这些事情的常用方法是使用多个进程。无论杀死一个子进程(不仅仅是访问冲突!)只会影响子进程,而不是可以做出相应反应的父进程。

标签: c++ multithreading


【解决方案1】:

一般不会。

访问冲突的一个主要原因是内存损坏 - 指向数据元素的指针被覆盖,或者某些对象的大小被擦除。一个进程中只有一个内存地址空间。最有可能发生这种情况的地方之一是newmalloc()分配的内存堆。每个进程只有一个堆。

因此,任何破坏内存的线程都会破坏所有线程的内存。

请注意,在您人为设计的示例中,您知道您正在引用一个空指针。实际代码中的问题是您永远不会知道为什么要取消引用空指针。如果您非法访问的内存不在地址 0 或某个非常接近它的值处,那么某些“杀死该线程以便其余线程能够生存”的逻辑永远无法真正知道发生了什么。

您可以尝试继续奔跑,就像您可以尝试穿过雷区一样。

如果你继续运行,你怎么知道你的结果是有效的?您几乎肯定永远不会测试过您的进程试图运行的确切内存损坏情况。因为如果你有,你就会知道那个错误并修复它,对吧?

如果你的线程在持有某种锁时死掉了,你会怎么做?

【讨论】:

    【解决方案2】:

    您可以使用sigaction 为 SIGSEGV 安装一个处理程序,该处理程序使该线程在 main 继续运行时保持忙碌。

    static void handler(int sig, siginfo_t* si, void* unused)
    {
        sleep(100000); // or something similar that's async-signal-safe
                       // on your operating system
    }
    
    int main(int argc, char *argv[])
    {
        struct sigaction sa;
        sa.sa_flags = SA_SIGINFO;
        sigemptyset(&sa.sa_mask);
        sa.sa_sigaction = handler;
        if (sigaction(SIGSEGV, &sa, NULL) == -1)
            perror("sigaction");
        ...
    

    这当然是难以置信的脆弱。例如,如果生成 SIGSEGV 的线程持有一个锁,那么它不会被释放以便其他线程可以获取它。

    正如 Ulrich 所指出的,容忍此类事情的通常方法是生成子进程。众所周知,谷歌 Chrome 早在几年前就开始为其浏览器选项卡执行此操作,这有助于它比当时的其他浏览器具有更高水平的弹性(后来他们不得不赶上自己)。现代操作系统使得拥有多个进程非常高效,而在旧操作系统中,线程可能使用的资源大大减少......

    【讨论】:

    • 希望没有什么在等待该线程完成...不过,它会“工作”。 :-)
    • 当然。你可以这样做。但是现在程序的状态如何?你怎么知道你从现在开始所做的任何事情都会产生正确的结果?还;这不会捕获所有崩溃。
    • @JesperJuhl:不知道你为什么问我。这取决于导致 SIGSEGV 的原因,Yura 可能会或可能不会对相关代码库中可能存在的内容有感觉......
    • @Tony 我不是在问你。我通过代理询问 OP。
    猜你喜欢
    • 1970-01-01
    • 2013-05-30
    • 2011-10-13
    • 1970-01-01
    • 2013-03-08
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    相关资源
    最近更新 更多