Linux 内核处理多线程吗?
Do Linux kernel processes multithread?
对于Linux 用户space 进程,确定哪些进程是多线程似乎很容易。您可以使用 ps -eLf 并查看线程数的 NLWP 值,它也对应于 '线程:' /proc/$pid/status 中的值。显然在 LinuxThreads 的那一天,实现不符合 POSIX。但是 This Whosebug answer 说“POSIX.1 要求线程共享相同的进程 ID”,这显然在 NPTL 中得到了纠正。因此,对于 NPTL,它允许使用 ps -eLf 等命令漂亮地显示线程,因为线程都共享相同的 PID,您可以在 / 下验证proc/$pid/task/ 并查看属于该 "parent" 进程的所有线程子文件夹。
对于 kthreadd 产生的内核进程,我在 "parent" 进程下找不到类似的线程分组,并且我怀疑实现差异,因为 this answer 下的评论说“您不能在内核中使用 POSIX 线程-space”,漂亮的线程分组是一个 POSIX 特性。因此,使用 ps -eLf 我从来没有看到为 kthreadd 创建的内核进程列出的多个线程,这些线程周围有方括号,例如 [ksoftirqd/0] 或 [nfsd ], 与 init.
创建的 user-space 进程不同
来自 pthreads 的手册页(在用户 space 中使用):
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).
然而,就包含多个线程的一个进程而言,这正是我在内核 "threads" 中所没有看到的。
简而言之,我从未见过 'ps' 列出的任何 kthreadd 子进程的 NLWP(线程)值高于 1,这使得我想知道 any 内核进程 forks/parallelizes 和像 user-space 程序这样的多线程是否可以(使用 pthreads)。实施方式有何不同?
实际例子:
NFS 进程的 psauxf 的输出。
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 "processes" 作为前端,为什么我不能将默认的 8 个不同的 nfsd 进程分组在一个 PID 下并拥有它下面有 8 个线程 运行,而(如图所示 - 与用户 space 进程不同)八个不同的 PID?
NSLCD 是用户 space 程序的示例,它使用多线程作为对比:
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 Whosebug answer:
kthreadd is a daemon thread that runs in kernel space. The reason is
that kernel needs to some times create threads but creating thread in
kernel is very tricky. Hence kthreadd is a thread that kernel uses to
spawn newer threads if required from there . This thread can access
userspace address space also but should not do so . Its managed by
kernel...
和this one:
kthreadd() is main function (and main loop) of daemon kthreadd which
is a kernel thread daemon, the parent of all other kernel threads.
So in the code quoted, there is a creation of request to kthreadd
daemon. To fulfill this request kthreadd will read it and start a
kernel thread.
内核中没有进程的概念,所以你的问题没有意义。 Linux 内核可以并且确实在内核上下文中完全创建 运行 线程,但是所有这些线程 运行 都在同一地址 space 中。没有按 PID 对相似线程进行分组,尽管相关线程通常具有相关名称。
如果多个内核线程正在处理同一个任务或以其他方式共享数据,那么它们需要通过锁定或其他并发算法来协调对该数据的访问。当然 pthreads API 在内核中不可用,但是可以使用内核互斥锁、等待队列等来获得与 pthread 互斥锁、条件变量等相同的功能
调用这些执行上下文"kernel threads" 是一个相当不错的名称,因为它们非常类似于用户space 进程中的多个线程。它们都共享(内核的)地址 space,但有自己的执行上下文(堆栈、程序计数器等),并且每个都独立调度并且 运行 并行。另一方面,内核实际上实现了所有漂亮的 POSIX API 抽象(在 userspace 中的 C 库的帮助下),因此在该实现的内部我们不有完整的抽象。
对于Linux 用户space 进程,确定哪些进程是多线程似乎很容易。您可以使用 ps -eLf 并查看线程数的 NLWP 值,它也对应于 '线程:' /proc/$pid/status 中的值。显然在 LinuxThreads 的那一天,实现不符合 POSIX。但是 This Whosebug answer 说“POSIX.1 要求线程共享相同的进程 ID”,这显然在 NPTL 中得到了纠正。因此,对于 NPTL,它允许使用 ps -eLf 等命令漂亮地显示线程,因为线程都共享相同的 PID,您可以在 / 下验证proc/$pid/task/ 并查看属于该 "parent" 进程的所有线程子文件夹。
对于 kthreadd 产生的内核进程,我在 "parent" 进程下找不到类似的线程分组,并且我怀疑实现差异,因为 this answer 下的评论说“您不能在内核中使用 POSIX 线程-space”,漂亮的线程分组是一个 POSIX 特性。因此,使用 ps -eLf 我从来没有看到为 kthreadd 创建的内核进程列出的多个线程,这些线程周围有方括号,例如 [ksoftirqd/0] 或 [nfsd ], 与 init.
创建的 user-space 进程不同来自 pthreads 的手册页(在用户 space 中使用):
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).
然而,就包含多个线程的一个进程而言,这正是我在内核 "threads" 中所没有看到的。
简而言之,我从未见过 'ps' 列出的任何 kthreadd 子进程的 NLWP(线程)值高于 1,这使得我想知道 any 内核进程 forks/parallelizes 和像 user-space 程序这样的多线程是否可以(使用 pthreads)。实施方式有何不同?
实际例子: NFS 进程的 psauxf 的输出。
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 "processes" 作为前端,为什么我不能将默认的 8 个不同的 nfsd 进程分组在一个 PID 下并拥有它下面有 8 个线程 运行,而(如图所示 - 与用户 space 进程不同)八个不同的 PID?
NSLCD 是用户 space 程序的示例,它使用多线程作为对比:
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 Whosebug answer:
kthreadd is a daemon thread that runs in kernel space. The reason is that kernel needs to some times create threads but creating thread in kernel is very tricky. Hence kthreadd is a thread that kernel uses to spawn newer threads if required from there . This thread can access userspace address space also but should not do so . Its managed by kernel...
和this one:
kthreadd() is main function (and main loop) of daemon kthreadd which is a kernel thread daemon, the parent of all other kernel threads.
So in the code quoted, there is a creation of request to kthreadd daemon. To fulfill this request kthreadd will read it and start a kernel thread.
内核中没有进程的概念,所以你的问题没有意义。 Linux 内核可以并且确实在内核上下文中完全创建 运行 线程,但是所有这些线程 运行 都在同一地址 space 中。没有按 PID 对相似线程进行分组,尽管相关线程通常具有相关名称。
如果多个内核线程正在处理同一个任务或以其他方式共享数据,那么它们需要通过锁定或其他并发算法来协调对该数据的访问。当然 pthreads API 在内核中不可用,但是可以使用内核互斥锁、等待队列等来获得与 pthread 互斥锁、条件变量等相同的功能
调用这些执行上下文"kernel threads" 是一个相当不错的名称,因为它们非常类似于用户space 进程中的多个线程。它们都共享(内核的)地址 space,但有自己的执行上下文(堆栈、程序计数器等),并且每个都独立调度并且 运行 并行。另一方面,内核实际上实现了所有漂亮的 POSIX API 抽象(在 userspace 中的 C 库的帮助下),因此在该实现的内部我们不有完整的抽象。