Linux内核是否处理多线程?

时间:2016-01-23 04:08:45

标签: multithreading linux-kernel kernel pthreads

对于Linux用户空间进程,确定哪些进程是多线程似乎很容易。您可以使用 ps -eLf 并查看 NLWP 值以获取线程数,这也对应于' 线程: ' / proc / $ pid / status 中的值。显然,在LinuxThreads的那一天,实现不符合POSIX标准。但是This stackoverflow answer说" POSIX.1要求线程共享相同的进程ID "这在NPTL中显然得到了纠正。因此,使用NPTL,它允许使用 ps -eLf 之类的命令显示线程,因为线程都共享相同的PID,您可以在 / proc / $ pid / task / 并查看属于该" parent"的所有线程子文件夹处理。

我无法在"父母"下找到类似的主题分组。由kthreadd生成的内核进程的进程,我怀疑实现的差异,因为this answer下的注释说" 你不能在内核空间中使用POSIX线程"并且漂亮的线程分组是POSIX功能。因此,对于 ps -eLf ,我从未看到为kthreadd创建的内核进程列出了多个线程,这些线程周围有方括号,如[ksoftirqd / 0]或[nfsd],不像用户空间进程创建的初始化。

从pthreads的手册页(在用户空间中使用):

       A single process can contain multiple threads, all of which are
       executing the same program.  These threads share the same global
       memory (data and heap segments), but each thread has its own stack
       (automatic variables).
然而,就一个包含多个线程的进程而言,这正是我没有看到的内核"线程"。

简而言之,我从来没有看到过&ps; ps'所列的任何流程。这是kthreadd的孩子,其 NLWP (线程)值高于1,这让我想知道任何内核进程是否/并行化和多线程如用户空间程序(用pthreads)。实施方式有何不同?

实际例子: 来自 ps auxf 的输出用于NFS进程。

root         2  0.0  0.0      0     0 ?        S    Jan12   0:00 [kthreadd]
root      1546  0.0  0.0      0     0 ?        S    Jan12   0:00  \_ [lockd]
root      1547  0.0  0.0      0     0 ?        S    Jan12   0:00  \_ [nfsd4]
root      1548  0.0  0.0      0     0 ?        S    Jan12   0:00  \_ [nfsd4_callbacks]
root      1549  0.0  0.0      0     0 ?        S    Jan12   2:40  \_ [nfsd]
root      1550  0.0  0.0      0     0 ?        S    Jan12   2:39  \_ [nfsd]
root      1551  0.0  0.0      0     0 ?        S    Jan12   2:40  \_ [nfsd]
root      1552  0.0  0.0      0     0 ?        S    Jan12   2:47  \_ [nfsd]
root      1553  0.0  0.0      0     0 ?        S    Jan12   2:34  \_ [nfsd]
root      1554  0.0  0.0      0     0 ?        S    Jan12   2:39  \_ [nfsd]
root      1555  0.0  0.0      0     0 ?        S    Jan12   2:57  \_ [nfsd]
root      1556  0.0  0.0      0     0 ?        S    Jan12   2:41  \_ [nfsd]

默认情况下,当您启动rpc.nfsd服务时(至少使用init.d服务脚本),它会生成8个进程(或者至少它们具有PID)。如果我想编写一个多线程版本的NFS,它是作为内核模块实现的,那就是那些nfsd"进程"作为前端,为什么我不能将默认的8个不同的nfsd进程分组在一个PID下并在其下运行8个线程,而不是(如图所示 - 和用户空间进程不同)八个不同的PID?

NSLCD是一个使用多线程的用户空间程序的例子:

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
nslcd     1424     1  1424  0    6 Jan12 ?        00:00:00 /usr/sbin/nslcd
nslcd     1424     1  1425  0    6 Jan12 ?        00:00:28 /usr/sbin/nslcd
nslcd     1424     1  1426  0    6 Jan12 ?        00:00:28 /usr/sbin/nslcd
nslcd     1424     1  1427  0    6 Jan12 ?        00:00:27 /usr/sbin/nslcd
nslcd     1424     1  1428  0    6 Jan12 ?        00:00:28 /usr/sbin/nslcd
nslcd     1424     1  1429  0    6 Jan12 ?        00:00:28 /usr/sbin/nslcd

PID是相同的,但每个线程的LWP是唯一的。

更新kthreadd的功能

来自this stackoverflow answer

  

kthreadd是一个在内核空间中运行的守护程序线程。原因是   内核需要创建一些线程但是创建线程   内核非常棘手。因此kthreadd是内核使用的线程   如果需要,从那里生成更新的线程。这个线程可以访问   用户空间地址空间也不应该这样做。它的管理   内核...

this one

  

kthreadd()是守护进程kthreadd的主要功能(和主循环)   是一个内核线程守护进程,是所有其他内核线程的父进程。

     

因此,在引用的代码中,创建了对kthreadd的请求   守护进程。为了满足这个要求,kthreadd将阅读它并开始一个   内核线程。

1 个答案:

答案 0 :(得分:8)

内核中没有进程的概念,所以你的问题确实没有意义。 Linux内核可以创建完全在内核上下文中运行的线程,但所有这些线程都在相同的地址空间中运行。虽然相关的线程通常具有相关的名称,但PID没有类似线程的分组。

如果多个内核线程正在处理相同的任务或以其他方式共享数据,那么他们需要通过锁定或其他并发算法来协调对该数据的访问。当然pthreads API在内核中是不可用的,但可以使用内核互斥,等待队列等来获得与pthread互斥,条件变量等相同的功能。

调用这些执行的上下文"内核线程"是一个相当好的名称,因为它们与用户空间进程中的多个线程非常相似。它们共享(内核)地址空间,但有自己的执行上下文(堆栈,程序计数器等),并且每个都是独立调度并且并行运行。另一方面,内核实际上实现了所有不错的POSIX API抽象(在用户空间中的C库的帮助下),因此内部的实现我们没有完全抽象。