Sel*_*ott 7 multithreading kernel pthreads linux-kernel
对于Linux用户空间进程,确定哪些进程是多线程似乎很容易.您可以使用ps -eLf并查看NLWP值以获取线程数,这也与/ proc/$ pid/status中的' Threads: '值相对应.显然,在LinuxThreads的那一天,实现不符合POSIX标准.但是这个stackoverflow回答说" POSIX.1要求线程共享一个相同的进程ID ",这显然在NPTL中得到了纠正.因此,使用NPTL,它允许使用ps -eLf之类的命令显示线程,因为线程都共享相同的PID,您可以在/ proc/$ pid/task /下验证 并查看属于该"父"进程的所有线程子文件夹.
我无法在kthreadd生成的内核进程的"父"进程下找到类似的线程分组,我怀疑实现的差异,因为在这个答案下的注释说" 你不能在内核空间中使用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).
Run Code Online (Sandbox Code Playgroud)
然而,就一个包含多个线程的进程而言,这正是我没有看到的内核"线程".
简而言之,我从来没有看到'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]
Run Code Online (Sandbox Code Playgroud)
默认情况下,当您启动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
Run Code Online (Sandbox Code Playgroud)
PID是相同的,但每个线程的LWP是唯一的.
更新kthreadd的功能
kthreadd是一个在内核空间中运行的守护程序线程.原因是内核需要有时创建线程,但在内核中创建线程非常棘手.因此,kthreadd是一个线程,如果需要,内核可以生成更新的线程.此线程也可以访问用户空间地址空间,但不应该这样做.它由内核管理...
而这一个:
kthreadd()是守护进程kthreadd的主要功能(和主循环),它是一个内核线程守护进程,是所有其他内核线程的父进程.
因此,在引用的代码中,创建了对kthreadd守护程序的请求.为了满足此请求,kthreadd将读取它并启动内核线程.
内核中没有进程的概念,所以你的问题确实没有意义.Linux内核可以创建完全在内核上下文中运行的线程,但所有这些线程都在相同的地址空间中运行.虽然相关的线程通常具有相关的名称,但PID没有类似线程的分组.
如果多个内核线程正在处理相同的任务或以其他方式共享数据,那么他们需要通过锁定或其他并发算法来协调对该数据的访问.当然pthreads API在内核中不可用,但可以使用内核互斥,等待队列等来获得与pthread互斥,条件变量等相同的功能.
调用这些执行上下文"内核线程"是一个相当好的名称,因为它们与用户空间进程中的多个线程非常相似.它们都共享(内核)地址空间,但有自己的执行上下文(堆栈,程序计数器等),并且每个都是独立调度并且并行运行.另一方面,内核实际上实现了所有不错的POSIX API抽象(在用户空间的C库的帮助下),因此内部的实现我们没有完全的抽象.