内核线程为什么需要内核线程
linux内核可以看作一个服务进程(管理软硬件资源,响应用户进程的种种合理以及不合理的请求) 。
内核需要多个执行流并行,为了防止可能的阻塞,支持多线程是必要的 。
内核线程就是内核的分身,一个分身可以处理一件特定事情 。内核线程的调度由内核负责,一个内核线程处于阻塞状态时不影响其他的内核线程,因为其是调度的基本单位 。
这与用户线程是不一样的 。因为内核线程只运行在内核态
因此,它只能使用大于PAGE_OFFSET(传统的x86_32上是3G)的地址空间 。
内核线程概述
内核线程是直接由内核本身启动的进程 。内核线程实际上是将内核函数委托给独立的进程,它与内核中的其他进程”并行”执行 。内核线程经常被称之为内核守护进程 。
他们执行下列任务
- 周期性地将修改的内存页与页来源块设备同步
- 如果内存页很少使用,则写入交换区
- 管理延时动作, 如2号进程接手内核进程的创建
- 实现文件系统的事务日志
- 线程启动后一直等待,直至内核请求线程执行某一特定操作 。
- 线程启动后按周期性间隔运行,检测特定资源的使用,在用量超出或低于预置的限制时采取行动 。
- 它们在CPU的管态执行,而不是用户态 。
- 它们只可以访问虚拟地址空间的内核部分(高于TASK_SIZE的所有地址),但不能访问用户空间
task_struct进程描述符中包含两个跟进程地址空间相关的字段mm, active_mm,
struct task_struct大多数计算机上系统的全部虚拟地址空间分为两个部分: 供用户态程序访问的虚拟地址空间和供内核访问的内核空间 。每当内核执行上下文切换时, 虚拟地址空间的用户层部分都会切换, 以便当前运行的进程匹配, 而内核空间不会放生切换 。
{
// ...
struct mm_struct *mm;
struct mm_struct *avtive_mm;
//...
};
对于普通用户进程来说,mm指向虚拟地址空间的用户空间部分,而对于内核线程,mm为NULL 。
这位优化提供了一些余地, 可遵循所谓的惰性TLB处理(lazy TLB handing) 。active_mm主要用于优化,由于内核线程不与任何特定的用户层进程相关,内核并不需要倒换虚拟地址空间的用户层部分,保留旧设置即可 。由于内核线程之前可能是任何用户层进程在执行,故用户空间部分的内容本质上是随机的,内核线程决不能修改其内容,故将mm设置为NULL,同时如果切换出去的是用户进程,内核将原来进程的mm存放在新内核线程的active_mm中,因为某些时候内核必须知道用户空间当前包含了什么 。
为什么没有mm指针的进程称为惰性TLB进程?
假如内核线程之后运行的进程与之前是同一个, 在这种情况下, 内核并不需要修改用户空间地址表 。地址转换后备缓冲器(即TLB)中的信息仍然有效 。只有在内核线程之后, 执行的进程是与此前不同的用户层进程时, 才需要切换(并对应清除TLB数据) 。
内核线程和普通的进程间的区别在于内核线程没有独立的地址空间,mm指针被设置为NULL;它只在 内核空间运行,从来不切换到用户空间去;并且和普通进程一样,可以被调度,也可以被抢占 。
内核线程的创建创建内核线程接口的演变
内核线程可以通过两种方式实现:
1、古老的接口 kernel_create和daemonize
将一个函数传递给kernel_thread创建并初始化一个task,该函数接下来负责帮助内核调用daemonize已转换为内核守护进程,daemonize随后完成一些列操作, 如该函数释放其父进程的所有资源,不然这些资源会一直锁定直到线程结束 。阻塞信号的接收, 将init用作守护进程的父进程
2、更加现在的方法kthead_create和kthread_run
创建内核更常用的方法是辅助函数kthread_create,该函数创建一个新的内核线程 。最初线程是停止的,需要使用wake_up_process启动它 。
使用kthread_run,与kthread_create不同的是,其创建新线程后立即唤醒它,其本质就是先用kthread_create创建一个内核线程,然后通过wake_up_process唤醒它
2号进程kthreadd的诞生
早期的kernel_create和daemonize接口
在早期的内核中, 提供了kernel_create和daemonize接口, 但是这种机制操作复杂而且将所有的任务交给内核去完成 。
但是这种机制低效而且繁琐, 将所有的操作塞给内核, 我们创建内核线程的初衷不本来就是为了内核分担工作, 减少内核的开销的么
推荐阅读
- Linux几种常见反弹shell,想成大牛的你必须了解
- 为什么单线程的Redis能够达到百万级的QPS?
- 一篇文章让你了解Linux进程调度器
- 快速修改Linux服务器远程端口方法
- Ubuntu更换默认终端
- 你需要知道的Linux后台服务器开发知识点
- Linux中文件的压缩和解压缩
- Linux在同一个服务器上运行Apache、Nginx和HAProxy
- Linux 安装mysql5.7.29源码安装
- 两个技巧帮你记住复杂 Linux 命令!