从实现的角度,我很好奇单个NPTL线程如何退出。
关于glibc-2.30的实现,我了解的是:
_exit()
syscall杀死线程组中的所有线程。pthread_create()
接受的用户功能实际上被包装到另一个功能pthread_create()
中,该功能在运行用户功能之前进行了一些准备,之后进行了一些清理。问题是:
包装函数start_thread()
的末尾,有以下注释和代码:
start_thread()
但是start_thread()
似乎还是要进行系统调用start_thread()
:
/* We cannot call '_exit' here. '_exit' will terminate the process.
The 'exit' implementation in the kernel will signal when the
process is really dead since 'clone' got passed the CLONE_CHILD_CLEARTID
flag. The 'tid' field in the TCB will be set to zero.
The exit code is zero since in case all threads exit by calling
'pthread_exit' the exit status must be 0 (zero). */
__exit_thread ();
所以我在这里很困惑,因为它实际上不应该执行syscall __exit_thread()
,因为它将终止所有线程。
__exit_thread()
应该终止单个线程,因此它应该执行与包装器_exit()
最后的操作类似的操作,但是它调用了 static inline void __attribute__ ((noreturn, always_inline, unused))
__exit_thread (void)
{
/* some comments here */
while (1)
{
INTERNAL_SYSCALL_DECL (err);
INTERNAL_SYSCALL (exit, err, 1, 0);
}
}
,而TBH在跟踪该函数时迷失了方向。它似乎与上述_exit()
无关,也没有调用pthread_exit()
。我在这里很困惑,因为它实际上不应该进行syscall _exit()
这里的混乱源于将pthread_exit()
系统调用与start_thread()
libc例程混合在一起(Linux上没有__do_cancel()
系统调用)。
前者终止当前的Linux线程(按预期方式。)>
后者(令人困惑)不执行__do_cancel()
系统调用。相反,它执行__exit_thread()
系统调用,该系统调用终止all
thread_exit()应该终止单个线程
它确实是间接的。它展开当前堆栈(类似于
_exit()
),执行控制转移到设置exit
的位置。那是在_exit
中。
在控制权转移之后,_exit
清理资源,并调用exit
实际终止线程。