内核如何将线程与进程分开

Dpk*_*Dpk 3 linux multithreading linux-kernel

假设我有一个像Firefox这样的浏览器进程,它有pid = 123. Firefox有5个打开的标签,每个标签都运行在一个单独的线程中,因此它总共有5个线程.

  1. 所以我想深入了解内核如何将进程分离到线程中以struct task_struct在thread_info中执行.

  2. Like struct task_struct是任务列表的任务描述符.哪里struct task_struct包含引用或这五个线程的链接.

  3. struct thread_struct像Firefox这样的进程是否包含对所有5个线程的引用

    要么

    每个线程都被视为Linux内核中的进程.

Ale*_*x D 13

与Windows不同,Linux在内核中没有"线程"的实现.内核为我们提供了有时被称为"轻量级进程"的东西,它们是"进程"和"线程"概念的概括,并且可以用来实现它们.

当您阅读内核代码并thread_struct一方面看到类似内容时,可能会感到困惑,而另一方面看到pid(进程ID).实际上,两者都是同一个.不要被术语混淆.

每个轻量级进程具有完全不同的thread_infotask_struct(与嵌入thread_struct).您似乎认为task_struct一个轻量级进程应该task_struct在同一个(用户空间)"进程"中指向其他(用户空间)"线程" 的s.不是这种情况.在内核中,每个"线程"都是一个单独的进程,调度程序分别处理每个"线程".

Linux有一个系统调用clone,用于创建新的轻量级进程.当您调用时clone,您必须提供各种标志,指示新进程与现有进程之间将共享的内容.他们可以共享他们的地址空间,或者他们每个人都可以拥有不同的地址空间.他们可以共享他们的打开文件,或者他们每个人都有自己的打开文件列表.他们可以共享信号处理程序,也可以各自拥有自己的信号处理程序.它们可以位于相同的"线程组"中,也可以位于不同的线程组中.等等...

虽然"线程"和"进程"在Linux中是相同的,但是您可以通过使用clone创建不共享其地址空间,打开文件,信号处理程序等的进程来实现我们通常认为的"进程" .

您还可以通过使用clone创建共享其地址空间,打开文件,信号处理程序等的进程来实现我们通常认为的"线程" .

如果你看一下它的定义task_struct,你会发现它有指向其他结构的指针,如mm_struct(地址空间),files_struct(打开文件),sighand_struct(信号处理程序)等等.当您clone使用新的"进程"时,将复制所有这些结构.当你clone有一个新的"线程"时,这些结构将在新旧s 之间共享task_struct - 它们将指向相同mm_struct,相同files_struct,等等.无论哪种方式,您只是提供不同的标志clone来告诉它要复制什么,以及分享什么.

我刚刚提到了上面的"线程组",所以你可能会对此感到好奇.简而言之,"进程"中的每个"线程"都有自己的PID,但它们都共享相同的TGID(线程组ID).TGID都等于第一个程序线程的PID.用户空间"PID",如在ps或中所示的那些/proc,实际上是内核中的"TGID".当然,clone有一个标志来确定一个新的轻量级进程是否会有一个新的TGID(因此将它放入一个新的"线程组").

UNIX进程也有"父"和"子".Linux中有指针task_struct实现父子关系.而且,正如您可能已经猜到的那样,clone有一个标志来确定新轻量级进程的父级将是什么.它可以是调用的进程,也可以是调用进程clone进程clone.你能弄清楚在创建"进程"时使用了哪个,在创建"线程"时使用了哪个?

查看联机帮助页clone; 这将是非常有教育意义的.还可以尝试strace使用pthreads查看clone正在使用的程序.

(其中很多都是从记忆中写出来的;其他人可以根据需要随意修改)

  • 真正的教育岗位.谢谢. (2认同)