multithreading - Linux内核是否处理多线程?

标签 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/ 下验证并查看属于的所有线程子文件夹那个“父”过程。

我无法在 kthreadd 生成的内核进程的“父”进程下找到类似的线程分组,并且我怀疑实现差异,因为 this answer 下的评论说“您不能在内核空间中使用 POSIX 线程”和漂亮的线程分组是一个 POSIX 功能。因此,使用 ps -eLf 我从来没有看到为由 kthreadd 创建的内核进程列出了多个线程,这些线程在其周围有方括号,例如 [ksoftirqd/0] 或 [nfsd],这与 init 创建的用户空间进程不同。

从 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”列出的任何进程是 kthreadd 的子进程,它们的 NLWP (线程)值大于 1,这让我想知道是否有任何内核进程 fork /并行化和多线程,如用户空间程序做(使用pthreads)。实现有什么不同?

实际例子:
NFS 进程的 ps auxf 的输出。
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 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 内核可以并且确实创建了完全在内核上下文中运行的线程,但是所有这些线程都在相同的地址空间中运行。尽管相关线程通常具有相关名称,但没有按 PID 对相似线程进行分组。

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

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

关于multithreading - Linux内核是否处理多线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34959506/

相关文章:

ruby-on-rails - Rails-将数据从后台作业传递到主线程

java - 多锁如何加速多线程代码?

module - Linux : order of statically linked module loading

linux-kernel - 初始化驱动程序时 module_init 和 subsys_initcall 有什么区别?

c - linux中的ls命令使用哪个linux系统调用来显示文件夹/文件名?

c++ - 按内核线程增量

C - 使用互斥锁时程序崩溃或不响应

linux - 尝试添加 FIFO 队列系统调用

c++ - linux getpid 系统调用错误

linux - 什么是抢占/什么是可抢占内核?到底有什么好处呢?