引子
看进程调度时,介绍优先级相同时的一些特殊处理,说当候选多给进程优先级相同时,一些倾向选择,有提到候选的进程和之前执行的进程有相同的进程空间时,会被优先选择。
而什么时候会出现这种两个进程使用相同的进程空间呢,说了两种情况,一个很熟悉的就是两个调度对象是痛一个进程中的两个线程对象时。
另一个说的是备选进程是内核线程时,这时这个线程会借用上个进程的地址空间。 那什么是内核线程??
内核线程:(感觉又踩了个大坑)
简述
网上搜的一个说的是内核线程,另一个经常混杂在一起说的时线程模型里面的 1对1,1对n之类的东西。
着两个东西是一个东西么,多半不是。两者什么关联呢?
感觉分别是 内核线程/内核进程/内核守护进程 和 内核级线程的两个概念。
先看一个说法-(内核级的线程)
linux对多线程的支持,要做的工作中很重要一部分集中在如何将用户级的线程映射到内核级的线程。
这里涉及到两个项目(概念):
NGPT(New Generation POSIX Thread):下一代POSIX线程
NPTL(Native POSIX Thread Library):本地POSIX线程库
为了减少分化,2002年 NGPT逐渐停止新增功能。NPTL成为新标准。pThread库使用NPTL。
对于cpu资源的调度分配,分配的对象被一些人称为内核级线程,其实就是链表中的一个链表元素。
linux里这个元素对于一个进程(一个线程也是一个特殊的进程)
所谓1:1模型,就时这个内核元素对应用户态一个进程(线程)。
除了1对1海域1对N,N对M,混合型,混合型应该和N对M不是同一个概念,有时间再细究。
怎么个1对N?
这些应该都是指对内核实现上。
如果应用层,比如像Go语言,对分配给自己的线程资源再做调度分配,这算1:N么?
网上所表述的内核级线程应该指的是内核调度的对象。用户态线程应该就时在进程中表现的代码执行流块。
再看另一个-内核守护进程
在使用ps查看线程的时候,CMD列会有不少[...]名称的线程,这些有别于其它线程,都是内核线程。
《unix环境高级编程》书中13章介绍系统进程:
父进程id为0的多为系统进程,……内核进程是特殊的通常存在于系统的整个生命周期中。它们以超级用户特权运行,无控制终端,无命令行。
ps输出实例中,内核守护进程的名字出现在方括号中。该(哪个)版本的Linux使用一个名为kthreadd的特殊内核进程来创建其他内核进程,所以kthreadd表现为其他内核进程的父进程。对于需要在进程上下文执行工作但却不被用户层上下文调用的每个内核组件,通常有它自己的内核守护进程。
(后面介绍了kswapd、flush、sync_supers、jbd这几个内核守护进程的工作职能。内核守护进程似乎是更标准通用的叫法)
inetd守护进程
nfsd、nfsiod、lockd、rpciod、rpc.idmapd、rpc.statd、rpc.mountd守护进程提供对网络文件系统(NFS)的支持。注意前4个是内核守护进程,后3个是用户守护进程。
守护进程终端名设置为问号
用户层守护进程的父进程是init进程
task_struct->mm是空指针,由于内核线程没有mm,所以在进程切换时,并不需要切换TLB,这就提供了优化。
为什么要分内核进程或线程,这,应用层程序都设计为多线程,内核功能代码也有同样设计的理由吧。
内核功能分多个线程(进程)来执行,来被调度,也减少不同功能之间的干扰。
进程运行的内核态和用户态切换,切换为内核态的时候,是复用/借用/调用某个内核守护进程来给自己执行需求么?我感觉不是,因为即使内核守护进程没有进程地址,它也是有自己独立任务的,一个侧面证明是,不同的进程或线程,都是有自己的内核栈的,内核守护进程也是。
个人认为线程执行系统调用进入内核态执行和原本一直都处于内核态的内核守护进程的某次被调度执行时两个不同的概念。
系统守护进程被调度,它是没有用户级的内存空间的,它应该也是不需要的,所以它可以直接借用之前被调度的进程的上下文(其实不是借用,而是用不到,也就省掉修改及做相关切换了),所以才有了进程调度时优先选择这一个可以减少切换的任务的说法。
其他不明确
而init似乎被称为系统守护进程。
《linux环境编程》中介绍 “PID上看,内核在kernel/pid.c中定义了RESERVED_PIDS,其值是300,300以下的pid会被系统占用,不分配给用户进程。”,那这些保留的PID时给这些内核线程的吗?
题外话
因为linux线程是复用进程的一套东西发展出来的,两者很多模糊的地方。网上很多时候喜欢把一些描述中进程的关键词又备注称为线程,可能是从标准理论的基础上来看的。
但是从实现的方面来看,有时候我个人更喜欢把线程当作进程来看,或者,特别是在调度的时候,把两者都统称为任务。
比如资料【3】中开头便说“我们通常说的 Linux 中的“进程”,实际对应的是“线程”,…”。我感觉反过来说更容易理解:线程实际是个进程,只是和主线程共享同一个进程地址。
参考资料:
【1】普通线程和内核线程 https://www.cnblogs.com/alantu2018/p/8526916.html
【2】内核调度模型(原文标题:关于内核线程、用户线程概念的理解) https://www.cnblogs.com/logo-fox/p/11057166.html
【3】linux线程实现机制分析 https://tcore.cloud/2019/06/21/linux-thread/
【4】https://www.jianshu.com/p/5a4fc2729c17
资料【2】并非原文,而且还把文章标题改了。文章下面标记了转自出处,但是那个原出处 文章,虽然有排版缩进,但是图片看不到了,到是【2】链接中图片还保留着,想了还是留【2】这个链接吧。
先记这么多,感觉这个支线已经花费太多了,以后再继续这块整理收集修正吧