由pthread_kill引起的分段错误。

9
GDB告诉我,pthread_kill在我的程序中导致了段错误。基本上,我正在使用pthread_kill通过给定ID来检查线程是否存活。
我一直在搜索网络,并发现可能是在TID无效时pthread_kill会导致段错误。是的,我一直在使用我构造的类型为int的“无效”TIDs对我的程序进行测试。这可能是真正的原因吗?

你使用了哪些“无效”的值? - Dan Fego
由于pthread_t是一个不透明的类型,使用整数(如1001)理论上可能会导致问题和随后的崩溃。在使用-Wall编译时,您是否收到任何警告? - Dan Fego
你有在valgrind下运行程序吗? - bdonlan
忽略我的先前评论,我正在查看旧的linuxthreads实现 :) - bdonlan
很遗憾,没有任何警告出现 :( - Terry Li
2个回答

16

pthread_t不是线程ID或数字索引,而是一个不透明类型。编造值可能会导致崩溃。

在Linux NPTL上,pthread_t被用作指针:

int
__pthread_kill (threadid, signo)
     pthread_t threadid;
     int signo;
{
  struct pthread *pd = (struct pthread *) threadid;

很明显,问题已经非常清楚了 :) 需要注意的是指针的实现细节 - 较早的Linuxthreads实现使用数字索引到一个表中,因此您确实可以编造TID而不期望崩溃。

您需要自己跟踪线程的生死。 pthread_t 在成功调用 pthread_join之前都是有效的。如果您想测试一个有效的 pthread_t 是否还活着,请在其上调用 pthread_tryjoin_np;如果它返回 EBUSY,则该线程仍然存在。如果函数成功,则 pthread_t不再有效;此时您不能重新使用它 - 因此您必须在某个地方记录该线程现在已经死亡,不需要再次检查它!

当然,您可以实现自己的跟踪系统 - 在某个地方创建一个存活表格,一个分配TID的系统,并将其传递到新创建的线程中。每个线程在退出之前标记自己为死亡(或许使用 pthread_cleanup_push处理线程取消和 pthread_exit),并分离线程,这样您就不需要加入它(使用pthread_detach)。现在您可以显式地控制您的线程死亡报告。


1
pthread_kill 的 man 手册说可以使用 pthread_kill(t, 0) 来“检查 t 是否存在”,这意味着可以使用无效的 pthread_t 值进行调用。那么,这个 man 手册是错误的吗? - Brandon
1
@Brandon 请参见http://sourceware.org/bugzilla/show_bug.cgi?id=4509和http://udrepper.livejournal.com/16844.html。Drepper的论点似乎相当不用心思,但看起来glibc没有支持对无效TID的pthread_kill,所以使用pthread_kill测试线程是否存在的方法不起作用。 - Joshua Clayton
POSIX非常清楚,在pthread_t的生命周期结束后使用它是未定义行为,并且POSIX 2008(原始或第一个TC,我忘记了)通过删除虚假的“可能失败”的错误进一步澄清了这一点。此外,未来的POSIX问题打算禁止对已退出但未被加入的线程使用ESRCH作为错误。 - R.. GitHub STOP HELPING ICE

2
为了解决代码中的这个限制,当代码没有运行时,我将TID设置为零。
memset(&thread, '\0', sizeof(pthread_t)); 

在调用pthread_kill之前,请检查它是否为null。

//this code will run if thread is not valid
if (!thread || ESRCH == pthread_kill(thread, 0)) {
    //do stuff and create the thread
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接