内核源代码:do_fork() 中的 parent_tidptr 和 child_tidptr 是什么?

baw*_*nal 6 kernel system-calls linux-kernel

在上述链接何谓parent_tidptrchild_tidptrdo_fork()其中创建新的进程?

mtk*_*mtk 5

让我们从原始系统调用接口开始。它因架构而异,但在 x86-64 上是:

   long clone(unsigned long flags, void *child_stack,
              int *ptid, int *ctid,
              unsigned long newtls);
Run Code Online (Sandbox Code Playgroud)

ptidctid是你parent_tidptrchild_tidptr。现在让我们看看clone(2)手册页是怎么说的:

   CLONE_CHILD_CLEARTID (since Linux 2.5.49)
          Erase  the  child  thread  ID  at the location ctid in
          child memory when the child exits, and do a wakeup  on
          the  futex  at that address.

   CLONE_CHILD_SETTID (since Linux 2.5.49)
          Store  the child thread ID at the location ctid in the
          child's memory.

   CLONE_PARENT_SETTID (since Linux 2.5.49)
          Store  the child thread ID at the location ptid in the
          parent's memory. 
Run Code Online (Sandbox Code Playgroud)

这些标志主要用于实现线程库。如果我们查看pthread_create()glibc 内部的 NPTL 实现,我们最终会发现其中的代码sysdeps/unix/sysv/linux/createthread.c进行了clone()包含CLONE_PARENT_SETTIDCLONE_CHILD_CLEARTIDin的调用flags

在那个clone()调用中,我们还可以看到ptidctid参数指向相同的地址。(请记住,POSIX 线程共享一个地址空间;这是通过clone() CLONE_VM标志实现的。)

所以,这里发生的事情如下。

  • CLONE_PARENT_SETTID用于确保内核线程 ID 存储在用户空间中的某个位置。线程实现的用户空间端需要知道该线程 ID。
  • CLONE_CHILD_CLEARTID当创建的线程clone()终止时,用于清除(即,零)相同的位置。

让我们走得更远一点......

经由返回的线程ID ptid/ctid相同的,为POSIX线程ID( pthread_t),虽然在1:1的线程实现,例如NPTL,有内核线程ID和POSIX线程ID之间的一对一的对应关系。内核线程 ID 与您使用 Linuxgettid()调用获得的 ID 相同。它也clone()作为系统调用返回值返回,这就提示了一个问题:为什么我们需要ptid/ ctid?问题是,从用户空间方面来看,事情是这样的:

tid = clone(...);
Run Code Online (Sandbox Code Playgroud)

从用户空间线程实现的角度来看,这里存在竞争,因为分配 totid clone()返回发生。这意味着如果用户空间线程库在新线程执行任何操作(例如终止)之前需要该信息,则它可能会遇到某些问题。UsingCLONE_PARENT_SETTID确保新线程 ID 放置在返回ptid 之前 指向的位置clone(),从而允许线程库避免这种竞争条件。(CLONE_CHILD_SETTID也可以用于类似的效果。)

CLONE_CHILD_CLEARTID用于清除ptid/的原因是ctidpthread_join()另一个线程中的调用提供一种方法来发现该线程已终止。本质上,ptid/ctid位置是作为futex使用的,futex()系统调用是用来阻塞的,等待这个位置的整数改变。(细节有点复杂,但grep对于glibc 源代码中的lll_wait_tid和 的使用lll_futex_wait。最终,发生了一个FUTEX_WAIT操作。回想一下,CLONE_CHILD_CLEARTID上面对目标地址进行了 futex 唤醒。)


Joh*_*éen 2

tid代表“线程 ID”。参数parent_tidptrchild_tidptr分别指向父进程地址空间和子进程地址空间中的用户空间内存。新创建的线程的 id 存储在指针指向的 int 变量中。

有关详细信息,请参阅clone(2)联机帮助页