为什么pthread_exit()在极少数情况下会在pthread_detach()之后调用时导致SEGV?

Wil*_*mKF 5 c++ centos pthreads segmentation-fault race-condition

我在C++中得到一个SEGV,在pthread_join()我的应用程序正在关闭时,我无法轻易地重现(它出现在大约100,000次测试运行中).我检查了errno的值,它是零.这是在Centos v4上运行的.

在什么条件下会pthread_join()获得SEGV?这可能是某种竞争条件,因为它非常罕见.一个人建议我不应该调用pthread_detach()和pthread_exit(),但我不明白为什么.

我的第一个工作假设是,pthread_join()pthread_exit()仍然在另一个线程中运行时被调用,并且这在某种程度上导致了SEGV,但是许多人已经说过这不是问题.

在应用程序退出期间在主线程中获取SEGV的失败代码看起来大致如此(为简洁起见,省略了错误返回代码检查):

// During application startup, this function is called to create the child thread:

return_val = pthread_create(&_threadId, &attr,
                            (void *(*)(void *))initialize,
                            (void *)this);

// Apparently this next line is the issue:
return_val = pthread_detach(_threadId);

// Later during exit the following code is executed in the main thread:

// This main thread waits for the child thread exit request to finish:

// Release condition so child thread will exit:
releaseCond(mtx(), startCond(), &startCount);

// Wait until the child thread is done exiting so we don't delete memory it is
// using while it is shutting down.
waitOnCond(mtx(), endCond(), &endCount, 0);
// The above wait completes at the point that the child thread is about
// to call pthread_exit().

// It is unspecified whether a thread that has exited but remains unjoined
// counts against {PTHREAD_THREADS_MAX}, hence we must do pthread_join() to
// avoid possibly leaking the threads we destroy.
pthread_join(_threadId, NULL); // SEGV in here!!!
Run Code Online (Sandbox Code Playgroud)

在退出时连接的子线程运行以下代码,该代码从releaseCond()主线程中调用的位置开始:

// Wait for main thread to tell us to exit:
waitOnCond(mtx(), startCond(), &startCount);

// Tell the main thread we are done so it will do pthread_join():
releaseCond(mtx(), endCond(), &endCount);
// At this point the main thread could call pthread_join() while we 
// call pthread_exit().

pthread_exit(NULL);
Run Code Online (Sandbox Code Playgroud)

线程似乎正确显示并且在应用程序启动期间创建期间没有生成错误代码,并且线程正确执行其任务,这在应用程序退出之前大约需要五秒钟.

什么可能导致这种罕见的SEGV发生,以及我如何针对它进行防御性编程.一个主张是我对pthread_detach()的调用是问题,如果是这样,我的代码应该如何纠正.

Nem*_*emo 4

假设:

  1. pthread_create返回零(你正在检查它,对吧?)
  2. attr是一个有效的pthread_attr_t对象(你如何创建它?为什么不直接传递 NULL 呢?)
  3. attr没有指定线程是分离创建的
  4. 您没有在其他地方调用pthread_detachpthread_join在线程上

...那么失败是“不可能”的pthread_join,并且您要么有其他内存损坏,要么在运行时出现错误。

[更新]

基本原理部分pthread_detach说:

最终应该为创建的每个线程调用 *pthread_join*() 或 *pthread_detach*() 函数,以便可以回收与线程关联的存储。

尽管它没有说这些是相互排斥的,但pthread_join文档指定:

如果 *pthread_join*() 的线程 参数指定的值不引用可连接线程,则行为未定义。

我很难找到确切的措辞来说明分离的线程不可连接,但我很确定这是真的。

因此,要么调用pthread_joinpthread_detach,但不能同时调用两者。