浅谈对内核的理解
内核
从操作系统的层面看,也可以分层。 硬件层、内核层、应用层。 内核就是用来连接硬件、应用层的桥梁。
所以,内核需要具备管理硬件的能力(决定内存用来做什么、决定哪个进程\线程使用CPU、决定设备之间的通信等等),向上还要有接口提供给应用。 也就是说,内核可以直接操作 内存和CPU,权限非常之高,非常危险
分层思想,在很多地方都存在,主要专注于各层负责各层的事,解耦合,在计算机网络里有分层,在微服务里也有分层。
内核的结构可以分为 宏内核monolithic kernel、微内核micro kernel、混合型内核。
宏内核: 内核负责了关于硬件的大部分事情。
微内核: 内核只保留了最基本的功能。大多数应用,比如程序驱动、文件系统是在用户空间管理的。体积小、可移植性强。但是驱动在内核外,驱动和硬件的交互就要频繁的切换到内核态。
混合型内核: 相当于在宏内核里面,抽象出了微内核,可以在大的结构里面增强功能。
Linux 内核, 是宏内核结构的。
特点:
多任务 mulitTask, 即并发,多个任务可以同时执行。
对称多处理 symmetric multiprocessing, 每个处理器地位平等,都可以访问完成的内存和硬件资源。
ELF , executable and linkable format , 可执行文件链接格式。 是 linxu 下的可执行文件的存储格式。把文件分为了一个个的段 segment。
Unix 和 Linux 非常相似, 也是宏内核结构的。
Windows 内核: 主流就是 NT 内核, new technology, 是混合型内核结构。
特点:
多任务、对称多处理。
PE, portable executable , 可移植执行文件。 是 windows 下的可执行文件格式。扩展名通常为
.exe
.dll
.sys
Mac OS 是 XNU 内核,混合型内核。 XNU: X is not Unix。
内核态和用户态
内核是一个完整的可执行程序。 程序启动后也会加载到内存里,成为一个进程。
内存里分为 用户空间、内核空间。
最小权限原则,多数应用程序都应该允许在最小的权限之下。 用户空间的代码只能访问用户态,内核空间的代码可以访问所有内存。
如果用户态想要操作硬件资源,就要发起系统调用,通过某种中断方式——trap,进入到内核态,从而提高权限。
进程: 程序启动后,会在内存中创建一个执行的副本,这个副本就是进程。通常的应用程序都是 用户态的进程。
Linux内核是一大段程序,启动之后也会加载到内存中,这是内核态的进程。
用户态进程想要申请 内存资源等, 就要通过 系统调用,向内核申请。
一个进程里可以有很多线程。 可以创建 用户态的线程,也可以通过系统调用创建 内核态的线程。
用户态线程
完全在用户空间创建,操作系统并不知道他的存在。
创建、销毁、切换线程不需要走系统调用,开销低。
但是无法利用多核的优势,操作系统调度的是他属于的哪个进程,也只能用分配到这个进程的时间片来执行,在这个进程里面的线程也不能 并行执行。当阻塞时,也要让出整个进程。
内核态线程
可以通过 系统调用创建一个内核态的线程。
创建、销毁成本高,需要系统调用切换到内核态。
可以利用多核CPU的优势,可以并行执行,操作IO时也不用进行系统调用切换到内核态提高权限。
用户态线程和内核态线程的映射
多对一: 多个用户态线程 复用 一个内核态线程,
也就是, 用内核态线程 来执行 用户态线程里的程序。
怎么执行? 程序就是存储在内存中的一些指令,让内核态的线程执行这些指令就可以。
一对一:
Windows NT 内核就是这种模型。
n对m:n个用户态线程 对 m个内核态线程。 m通常小于n,m一般为CPU的核数。
Linux 内核的 NGPL 实现了这种模型。但目前都是 一对一模型。
Linux 的 PThreadAPI 创建 用户态线程; KThreadAPI创建 内核态线程。