如何在 Linux 上实现 pthread_detach?

How can one implement pthread_detach on Linux?

pthread_detach 标记一个线程,这样当它终止时,它的资源会自动释放而不需要 parent 线程调用 pthread_join。它怎么能做到这一点?特别是从Linux的角度来看,有两个资源我特别好奇:

  1. 作为一个实现细节,我希望如果 wait 系统调用没有在终止的线程上执行,那么该线程就会变成僵尸。我假设 pthread 库对这个问题的解决方案不涉及 SIGCHLD,因为(我认为)无论程序指定在接收到 SIGCHLD 时发生什么动作,它仍然有效。
  2. 线程是使用 clone 系统调用创建的。调用者必须在调用 clone 之前分配内存作为 child 线程的堆栈区。 Elsewhere on Stack Overflow,建议调用者使用mmap为child分配堆栈。线程退出后如何解除栈映射?

在我看来 pthread_detach 必须以某种方式为这两个问题提供解决方案,否则,产生和分离许多线程的程序最终将失去继续产生新线程的能力,即使分离线程可能已经终止。

pthreads 库(在 Linux、NPTL 上)提供了一个围绕低级原语的包装器,例如 clone(2)。当使用 pthread_create 创建线程时,传递给 clone 的函数是一个包装函数。该函数分配堆栈并将该信息和任何其他元数据存储到一个结构中,然后调用用户提供的启动函数。当用户提供的启动函数 returns 时,会进行清理。最后调用内部函数__exit_thread进行系统调用退出线程

当这样的线程被分离时,它仍然 returns 从用户提供的启动函数中调用清理代码,除了堆栈和元数据作为其中的一部分被释放,因为没有人在等待为了完成这个线程。这通常由 pthread_join.

处理

如果一个线程在没有 运行 的情况下被终止或退出,则清理由下一个 pthread_create 调用处理,它将调用尚未成为 运行 的任何清理处理程序。

SIGCHLD 没有发送给父级也不需要 wait(2) 的原因是因为使用了 clone(2)CLONE_THREAD 标志。手册页对这个标志说了以下内容:

A new thread created with CLONE_THREAD has the same parent process as the process that made the clone call (i.e., like CLONE_PARENT), so that calls to getppid(2) return the same value for all of the threads in a thread group. When a CLONE_THREAD thread terminates, the thread that created it is not sent a SIGCHLD (or other termination) signal; nor can the status of such a thread be obtained using wait(2). (The thread is said to be detached.)

如您所述,这是发生预期的 POSIX 语义所必需的。