内核如何将线程与进程

时间:2015-06-15 07:47:09

标签: linux multithreading linux-kernel

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

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

  2. 类似struct task_struct是任务列表的任务描述符。 struct task_struct在哪里包含这五个主题的引用或链接。

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

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

1 个答案:

答案 0 :(得分:12)

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

当您阅读内核代码并且一方面看到thread_struct和另一方面pid(进程ID)之类的内容时,可能会感到困惑。实际上,两者都是同一个。不要被术语搞糊涂。

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

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

虽然"线程"和"进程"在Linux中是一样的,你可以实现我们通常认为的"进程"使用clone创建不共享其地址空间,打开文件,信号处理程序等的流程。

你也可以实现我们通常认为的"线程"使用clone创建 DO共享其地址空间,打开文件,信号处理程序等的流程。

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

我刚刚提到了#34;线程组"以上,所以你可能想知道这一点。简而言之,每个"线程"在一个"过程"有自己的PID,但它们都共享相同的TGID(线程组ID)。 TGID都等于第一个程序线程的PID。用户空间" PID",如cloneps中显示的那些,实际上是" TGID"在内核中。当然,/proc有一个标志来确定一个新的轻量级进程是否会有一个新的TGID(因此将它放入一个新的"线程组")或不。

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

查看clone的联系人页面;这将是非常有教育意义的。另请尝试使用pthreads查看正在使用的clone的程序strace

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