我遇到了
pthread_detach
的一些意外行为。考虑以下代码:
#include <pthread.h>
int main() {
pthread_detach(0);
}
这显然是一个错误(0 不是有效的
pthread_t
)。当我运行此代码时,进程因段错误而崩溃。
问题是,根据手册页,它应该处理这个错误并简单地返回ESRCH(因为这应该只是“没有找到ID为0的线程”的情况,对吧?)
手册页提到的唯一未定义的行为是尝试分离已经分离的线程,但事实并非如此。
我使用的是 glibc 版本 2.39-4.2;这可能是一个错误吗?
更新:我在这里找到了负责此操作的代码:https://elixir.bootlin.com/glibc/glibc-2.39/source/nptl/pthread_detach.c#L29
因此,手册页中的“线程ID”似乎指的是线程结构的某些属性(tid,请参阅here)(由
pthread_t
类型指向。这解释了段错误,但我仍然不相信这是预期的行为。
更新2:我刚刚遇到这个非常相关的问题,这似乎几乎回答了这个问题。
当您用
glibc
标记您的问题时,答案就在 GLIBc 源代码中。源文件是:nptl/pthread_detach.c
int
pthread_detach (pthread_t th)
{
struct pthread *pd = (struct pthread *) th;
/* Make sure the descriptor is valid. */
if (INVALID_NOT_TERMINATED_TD_P (pd))
/* Not a valid thread handle. */
return ESRCH;
int result = 0;
/* Mark the thread as detached. */
if (atomic_compare_and_exchange_bool_acq (&pd->joinid, pd, NULL))
{
/* There are two possibilities here. First, the thread might
already be detached. In this case we return EINVAL.
Otherwise there might already be a waiter. The standard does
not mention what happens in this case. */
if (IS_DETACHED (pd))
result = EINVAL;
}
else
/* Check whether the thread terminated meanwhile. In this case we
will just free the TCB. */
if ((pd->cancelhandling & EXITING_BITMASK) != 0)
/* Note that the code in __free_tcb makes sure each thread
control block is freed only once. */
__free_tcb (pd);
return result;
}
使用
INVALID_NOT_TERMINATED_TD_P (pd)
检查传递给 API 的参数。如果检查失败,则返回 ESRCH,但后者在 nptl/pthreadP.h 中定义为:
/* Simplified test. This will not catch all invalid descriptors but
is better than nothing. And if the test triggers the thread
descriptor is guaranteed to be invalid. */
# define INVALID_TD_P(pd) __builtin_expect ((pd)->tid <= 0, 0)
# define INVALID_NOT_TERMINATED_TD_P(pd) __builtin_expect ((pd)->tid < 0, 0)
上面的宏不会检查参数是否有效(至少不等于0)以使用
(pd)->tid
取消引用它。这就是你崩溃的原因。