调用 pthread_join() 两次时 glibc pthread_join 崩溃

Posted

技术标签:

【中文标题】调用 pthread_join() 两次时 glibc pthread_join 崩溃【英文标题】:glibc pthread_join crash when call pthread_join() twice 【发布时间】:2017-08-16 00:45:48 【问题描述】:

我使用 POSIX pthread 库编写了以下代码:

#include <stdlib.h>
#include <pthread.h>

void *thread_function(void *arg) 
    char *code = "1";


int main() 
int res;
pthread_t a_thread;
void *thread_result;

res = pthread_create(&a_thread, NULL, thread_function, NULL);
if (res != 0) 
    perror("Thread creation failed");
    exit(EXIT_FAILURE);


sleep(5);
printf("\nWaiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result);
printf("res[%d]\n",res);
if (res != 0) 
    perror("Thread join failed");
    exit(EXIT_FAILURE);

res = pthread_join(a_thread, &thread_result);
printf("res[%d]\n",res);
exit(EXIT_SUCCESS);

在执行代码时,我得到以下输出:

Waiting for thread to finish...
res[0]
Segmentation fault (core dumped)

在代码中,我想测试如果调用 pthread_jion() 函数会发生什么 线程完成后两次。第一次调用该函数是正确的,第二次崩溃。回溯:

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  pthread_join (threadid=140150565050112, thread_return=0x7fffa0a2c508) at 
pthread_join.c:47
47    if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
Python Exception exceptions.ImportError No module named gdb.frames: 
#0  pthread_join (threadid=140150565050112, thread_return=0x7fffa0a2c508) at 
pthread_join.c:47
#1  0x00000000004008d5 in main ()

我检查了 pthread_join.c 文件:

39 int
40 pthread_join (threadid, thread_return)
41      pthread_t threadid;
42      void **thread_return;
43 
44   struct pthread *pd = (struct pthread *) threadid;
45 
46   /* Make sure the descriptor is valid.  */
47   if (INVALID_NOT_TERMINATED_TD_P (pd))
48     /* Not a valid thread handle.  */
49     return ESRCH;

在第 47 行,宏定义检查 pd 是否是有效的线程句柄。如果不是,则返回 ESRCH(3)。

但是,当我在另一个 Linux 环境中运行相同的代码时,我得到了以下输出:

Waiting for thread to finish...
res[0]
res[3]

这和环境有关系吗?两个linux系统的ldd版本相同:

ldd (GNU libc) 2.17

相同的 GLIBC:

GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_3.4.20
GLIBC_2.3
GLIBC_2.2.5
GLIBC_2.14
GLIBC_2.17
GLIBC_2.3.2
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGT

和相同的linux内核版本:

Red Hat Enterprise Linux Server release 6.6 (Santiago)

【问题讨论】:

【参考方案1】:

pthread_join 在线程终止后调用pthread_detachpthread_detach在线程终止时释放所有线程资源。

来自pthread_detach的文档

尝试分离已经分离的线程会导致 未指定的行为。

所以你有未指定的行为,所以你不能保证之后会发生什么。

至少,threadid 指向的内存将被释放,从而访问释放的内存。

简而言之,不要在同一个 threadid 上调用 pthread_join 两次。为什么要这样做?

编辑:更简单:pthread_join 的手册页说:

加入之前已加入的线程会导致 未定义的行为。

【讨论】:

以上是关于调用 pthread_join() 两次时 glibc pthread_join 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

当在 2 个连续的行中调用两次时,Faker 正在生成重复数据(Typescript)

AWS.ApiGatewayManagementApi.postToConnection() 调用一次时执行两次

MPMoviePlayerController 仅在调用两次时播放。仅在 iOS 4 中出现

React Navigator StackNavigator:从同一场景调用两次时 goBack 不起作用

使用一个参数调用 pthread_join 会导致分段错误?

当一个模块被导入两次时会发生啥?