简体   繁体   English

工作者线程堆栈溢出时的信息出口

[英]Informative exit on stack overflow in worker thread

I'm writing a C++ program which is going to run a bunch of worker threads on recursive data, such that even though I've increased the default stack space, it's possible that a thread might hit a stack overflow. 我正在编写一个C ++程序,该程序将在递归数据上运行一堆工作线程,这样,即使我增加了默认的堆栈空间,线程也有可能遇到堆栈溢出。

The ideal would be to have the stack dynamically expand as needed, but if that's not possible, it's acceptable to have the program fail, and for the user to retry after recompiling it with a larger stack size. 理想的做法是使堆栈根据需要动态扩展,但是如果不可能,则可以使程序失败,并让用户在使用较大的堆栈大小重新编译后重试。

The problem with the default behavior of the program crashing with no error message is that the user has no way of knowing what the problem was or what to do about it; 程序默认行为崩溃而没有任何错误消息的问题是用户无法知道问题出在哪里或如何解决。 for all the user knows, the program might have tried to divide by zero or dereference a null pointer; 就用户所知,该程序可能试图除以零或取消引用空指针; so if the program must crash, I'd like it to print "Stack overflow" to stderr first. 因此,如果程序必须崩溃,我希望它首先将“ Stack Overflow”打印到stderr。

Obviously there isn't going to be a solution in portable C++ but I would be happy with one solution that works on Windows and another that works on Linux. 显然,在便携式C ++中不会有一种解决方案,但是我对一种适用于Windows的解决方案和另一种适用于Linux的解决方案感到满意。

Looking at ways to have the program exit with an informative error message on Windows, I've been reading the documentation on vectored and structured exception handling; 在寻找使程序在Windows上退出并显示提示性错误消息的方法时,我一直在阅读有关矢量化和结构化异常处理的文档。 one problem is that these seem to be local to a thread, and a thread can't safely write to stderr; 一个问题是它们似乎是线程本地的,并且线程不能安全地写入stderr。 at best you get a race condition. 最好情况下,您会遇到种族问题。

Is there a known method of dealing with this? 有已知的处理方法吗?

The OS (Linux or Unix flavours at least) allow you to catch stack faults. 该操作系统(至少具有Linux或Unix风格)使您能够捕获堆栈故障。

Something like this: 像这样:

 // Note: Calling printf here is probably not a brilliant idea, 
 // as we're in a signal handler. It is NOT well-defined what happens.
 void handler(int arg)
 {
    fprintf(stderr, "Crashed due to signal handler\n"); 
    exit(42);
 }

Then in main or some such ... 然后主要是这样的...

 struct sigaction sa = { handler, NULL, 0, 0, NULL };
 struct sigaction oldsa;
 sigaction(SIGSTKFLT, sa, oldsa);

I will try to come up with a bit more of a "complete" solution, with some experiments in a bit. 我将尝试提出一些“完整”的解决方案,并进行一些实验。

(I believe it is possible to replace the stack, but I don't think you can, in a meaningful way, actually continue at that point, just allows you to recover in a more sane way than simply crashing!) (我相信可以替换堆栈,但我认为您不能以有意义的方式实际上继续执行该操作,而只是让您以比崩溃更明智的方式恢复!)

This APPEARS to work: 这似乎可以正常工作:

#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <cstdlib>

void handler(int arg)
{
    write(2, "stack overflow\n", 15);
    _exit(42);
}

void* duh(void *arg)
{
    if(duh(arg))
    {
        return duh(NULL);
    }
    else
    {
        return duh(arg);
    }
}

void* crash_wrapper(void *arg)
{
    static char stack[SIGSTKSZ];
    stack_t ss = {};
    ss.ss_sp = stack;
    ss.ss_size = SIGSTKSZ;
    sigaltstack(&ss, 0);

    struct sigaction sa = {};
    sa.sa_handler = handler;
    sa.sa_flags = SA_ONSTACK,
    sigfillset(&sa.sa_mask);
    sigaction(SIGSEGV, &sa, 0);

    return duh(arg);
}

int main()
{
    pthread_t t;
    int status = pthread_create(&t, 0, crash_wrapper, 0 );

    for(;;)
    {
        std::cout << "Still going..." << std::endl;
        sleep(1);
    }
}

I'm not entirely happy with the write inside the handler, but all other methods that I tried didn't seem to work either... :( 我对处理程序中的write不完全满意,但是我尝试过的所有其他方法似乎也不起作用... :(

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM