我正在编写一个C ++程序,它将在递归数据上运行一堆工作线程,这样即使我增加了默认的堆栈空间,也可能是线程可能遇到堆栈溢出。
理想情况是让堆栈根据需要动态扩展,但如果不可能,那么让程序失败是可以接受的,并且用户可以在用更大的堆栈大小重新编译它之后重试。
程序的默认行为崩溃且没有错误消息的问题是用户无法知道问题是什么或该怎么办;对于所有用户都知道,程序可能试图除以零或取消引用空指针;所以如果程序必须崩溃,我希望它首先将“Stack overflow”打印到stderr。
显然在便携式C ++中不会有解决方案,但我会对一种适用于Windows的解决方案和另一种适用于Linux的解决方案感到满意。
在Windows上查看使用信息性错误消息退出程序的方法,我一直在阅读有关向量和结构化异常处理的文档;一个问题是这些似乎是一个线程本地的,一个线程无法安全地写入stderr;充其量你会遇到竞争条件。
有没有一种已知的处理方法?
答案 0 :(得分:1)
OS(至少Linux或Unix风格)允许您捕获堆栈错误。
这样的事情:
// 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);
}
然后在主要或某些......
struct sigaction sa = { handler, NULL, 0, 0, NULL };
struct sigaction oldsa;
sigaction(SIGSTKFLT, sa, oldsa);
我会尝试提出一些“完整”的解决方案,并进行一些实验。
(我相信有可能更换堆栈,但我认为你不能以一种有意义的方式实际上继续这一点,只是让你以更加理智的方式恢复,而不仅仅是崩溃!)< / p>
这个出现的工作:
#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);
}
}
我对处理程序中的write
并不完全满意,但我尝试的所有其他方法似乎都不起作用...... :(