保护主线程免受工作线程中的错误的影响

时间:2014-09-22 09:38:39

标签: c++ c pthreads signals posix

使用posix线程时,是否有某种方法可以“保护”主线程免受工作线程引起的错误(例如解除引用的空指针,除零等)。 “工作线程”是指由pthread_create()创建的posix线程。

不幸的是,我们不能使用例外 - 所以没有“捕获”等等。

这是我的测试程序(C ++):

void* workerThreadFunc(void* threadId) {
  int* a = NULL;
  *a = 5; //Error (segmentation fault)
  pthread_exit(NULL);
}

int main() {
  cout << "Main thread start" << endl;

  pthread_t workerThread;
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_create(&workerThread, &attr, workerThreadFunc, (void*)0);
  pthread_join(workerThread, NULL);

  cout << "Main thread end" << endl;
}

在上面的示例中,workerThread引起的错误将终止整个程序。但我希望主线程继续运行,尽管这个错误。这有可能实现吗?

3 个答案:

答案 0 :(得分:8)

听起来我应该使用多个进程,而不是线程。独立进程会自动受到保护,免受其他进程中发生的这类错误的影响。

您可以使用管道或共享内存(或其他形式的IPC)在线程之间传递数据,这样做的另一个好处就是只共享您想要共享的内存,因此工作者“线程”中的错误无法踩踏主“线程”的堆栈,因为它是一个单独的进程,具有单独的地址空间。

线程可能很有用,但有几个缺点,有时在单独的进程中运行更合适。

答案 1 :(得分:5)

我能想到这样做的唯一方法是注册一个信号处理程序,它可以取代当前运行的线程,而不是中止程序,如下所示:

void handler(int sig)
{
    pthread_exit(NULL);
}

signal(SIGSEGV, handler);

但请注意,这是不安全的,因为pthread_exit未列为信号处理程序内的安全系统调用之一。它可能会起作用,也可能不起作用,这取决于您正在运行的O / S,以及您正在处理的信号。

答案 2 :(得分:4)

假设您的系统在某种程度上使用POSIX中的信号(尽管可能属于&#34;没有例外&#34;规则),那么POSIX说:

  

在生成时,应确定是为过程生成了信号还是为过程中的特定线程生成了信号。应该为导致生成信号的线程生成由特定线程的某些操作(例如硬件故障)生成的信号。

因此,您可以在每个pthread的基础上处理SIGSEGVSIGFPE等(但请注意,您只能为整个过程设置一个信号处理函数)。所以,你可以保护&#34;由于单个pthread失败而停止死亡的过程......直到某一点。当然,问题在于你可能会发现很难分辨出进程的状态 - 失败的pthread和所有其他的pthreads - 失败的pthread可能会持有多个互斥锁。失败的pthread可能会使一些共享数据结构混乱。谁知道什么样的纠结事物 - 除非pthreads基本上是独立的。也许可以安排其他pthreads优雅地关闭&#34; ...而不是崩溃和燃烧。最终,它可能更安全地阻止所有pthreads死亡,而不是试图继续在一些不太明确的状态。它完全取决于应用程序的性质。

没有什么是无用的......线程可以比流程更容易地相互通信,并且启动和停止成本更低 - 流程不易受到其他流程失败的影响。