如何在 Linux 上实现 pthread_detach?
How can one implement pthread_detach on Linux?
pthread_detach
标记一个线程,这样当它终止时,它的资源会自动释放而不需要 parent 线程调用 pthread_join
。它怎么能做到这一点?特别是从Linux的角度来看,有两个资源我特别好奇:
- 作为一个实现细节,我希望如果
wait
系统调用没有在终止的线程上执行,那么该线程就会变成僵尸。我假设 pthread 库对这个问题的解决方案不涉及 SIGCHLD
,因为(我认为)无论程序指定在接收到 SIGCHLD
时发生什么动作,它仍然有效。
- 线程是使用
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 语义所必需的。
pthread_detach
标记一个线程,这样当它终止时,它的资源会自动释放而不需要 parent 线程调用 pthread_join
。它怎么能做到这一点?特别是从Linux的角度来看,有两个资源我特别好奇:
- 作为一个实现细节,我希望如果
wait
系统调用没有在终止的线程上执行,那么该线程就会变成僵尸。我假设 pthread 库对这个问题的解决方案不涉及SIGCHLD
,因为(我认为)无论程序指定在接收到SIGCHLD
时发生什么动作,它仍然有效。 - 线程是使用
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 语义所必需的。