计算机操作系统处理机调度读后感—–关于进程概念的剖析。从RING3到RING0(32位操作系统)
计算机操作系统处理机调度读后感:
笔者在看操作系统西安电子科技大学那本书的时候,初次感觉本科教的不会太难,所以没有认真的看,但是随后这本书讲的刷新了我的世界观。这本书居然是ring0级别的,这时不禁吐槽一下。。如果没调试过程序,没接触过ring0的同学,这本书就和马原一样。全背完还不知道学了啥。
由于笔者之前做过逆向工程。而调试的大都是ring3级别的,这本书是ring0级别的。我必须要把这些知识和之前学的连接起来,以便以后接触ring0的时候能更轻松一些。
1、创建进程。
在这个模块我会从一个创建进程的函数开始,将我知道的进程线程等内核对象与目前看的这本书联系起来。
ps:当你双击一个桌面一个exe执行文件的时候,实际上是一个名叫explorer.exe的进程帮你去创建一个进程。如果你把这个进程终结了的话你会发现图标及任务栏全没了。刚刚启动的窗口却还在。没了父进程的我们一般称作孤儿进程。(笑)

这是win32api给出的创建进程的方法。下面是对于创建进程需要的参数。
1、作业调度参数
IpApplicationName 一般填入文件路径。指向一个NULL结尾的、用来指定可执行模块的字符串。说白了告诉程序要从哪把PE文件拽入内存中(这个过程一般称为作业调度)。
lpCommandLine指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。 可以把他理解为main方法中的参数argv[]。
dwCreationFlags一般设置进程的优先级,和其他细节操作。有很多参数网上都有。没啥用。
2、进程通信参数
lpProcessAttributesh、lpThreadAttributesh和bInheritHandles
这三个参数分别是子进程是否继承父进程的句柄表。如果继承了的话,子类可以访问其他父类创建的进程。话说回来我觉得这个就是属于操作系统进程通信中的共享存储器系统 。通过共享句柄表,来进行子进程和父进程的通信。
而线程在笔者心中和进程一样,都是属于内核对象。原因很简单,他们都有自己的句柄。而且在程序中都叫Handle。很多人认为线程比进程要矮一级,笔者认为这是错的。进程是提供资源的,例如:PE文件在装入内存后(作业调度)在内存中分配各种代码段,数据段,堆栈,还有各种其他信息。而线程则是执行这些代码段,享用这些堆栈的。
一个进程如果没了线程就会被杀死,因为进程的存在是没有意义的,空占内存!
3、各种作业调度的各种细节函数(没啥用,一般给NULL就行)
lpEnvironment
指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
lpCurrentDirectory
指定子进程的工作路径。
lpStartupInfo
启动信息。
lpProcessInformation
进程信息
2、进程调度
1、虚拟内存
笔者这里需要引入一个虚拟内存的概念,这个虚拟内存不同于这本书后面的虚拟内存存储器,(那个虚拟内存为了解决有的作业比较大,内存一时不够用了而创建的一种分配机制)。
这里借用一下0day安全那本书的一张图

虽然每个进程都“相信”自己拥有 4GB 的空间,但实际上它们运行时真正能用到的空间根本没有那么多。内存管理器只是分给进程了一片“假地址”,或者说是“虚拟地址”,让进程们“认为”这些“虚拟地址”都是可以访问的。如果进程不使用这些“虚拟地址”,它们对进程来说就只是一笔“无形的数字财富”;当需要进行实际的内存操作时,内存管理器才会把“虚 拟地址”和“物理地址”联系起来
2、而为什么是4GB的虚拟内存呢?
这里我给出计算虚拟内存的方法
我们日常的操作系统是32位的,这个4GB的虚拟内存就是32位操作系统的特性。
32位最小的地址是0000 0000 最大是 FFFF FFFF 这里是十六进制表示的!!

可以看到十进制是4,294,967,295 加上0000 0000这个地址,总共就是4294967296
而4294967296 代表的是可以存的Byte字节。1024B=1KB
1024KB=1M 1024M=1G
根据这个我们可以算出结果位4GB。所以这不是定义的,而是算出来的。
3、高2G和低2G
在内存中7FFFF FFFF之前的我们称之为低2G也就是所谓的ring3用户态
而从8000 0000开始就是所谓的ring0内核级了,普通调试器例如Ollydbg是无法对ring0进行调试的。
而ring0就保存了处理机的现场信息,操作系统内核代码、设备驱动程序、设备I/O高速缓存、非页面内存池的分配、页表等一切后面的章节所讲的知识。
(笔者对于之前的自大有点羞愧,之前认为本科教材很简单,思想是有点不准确的)
4、进程调度(原书3.3)
下面就是完完全全的ring0级别的了,是普通程序员在开发时完全体会不到的,因为无论是windows编程还是Java,Linux编程那些都是应用层面的开发。ring0级别的是完全透明的无法感知的。
因为我这次是以我最熟悉的windows的平台进行的讲解。而windows属于多用户多任务型操作系统,进程调度相对复杂,而微软的封闭性导致我学习的困难,因此我对进程调度的学习还是以书上的相对简单的实现方式进行讲解。(这本书关于算法讲的也太简单了。连个数据结构都没有,差评。)
(0)PCB进程控制块的介绍:
(1)进程调度的任务(原书3.3.1)
1.保存处理机的现场信息。—这个比较好理解,把各种结构体压进系统堆栈(push)中即可实现保存。
2.按照某种算法选取进程。—-笔者认为这里是个坑。因为没有数据结构哪来的算法,所以还是往后再深究。
3.把处理器分配给进程。—-笔者也不知道如何分配的,书上也没有具体介绍,姑且理解为弹栈(pop)的过程把。
三、进程调度算法
在这里,我主要介绍俩种进程调度算法的实现、轮转法和优先级调度算法。
一、轮转法:
一.轮转法的基本原理:
根据先来先服务的原则,将需要执行的所有进程按照到达时间的大小排成一个升序的序列,每次都给一个进程同样大小的时间片,在这个时间片内如果进程执行结束了,那么把进程从进程队列中删去,如果进程没有结束,那么把该进程停止然后改为等待状态,放到进程队列的尾部,直到所有的进程都已执行完毕
二.进程的切换
时间片够用:意思就是在该时间片内,进程可以运行至结束,进程运行结束之后,将进程从进程队列中删除,然后启动新的时间片
时间片不够用:意思是在该时间片内,进程只能完成它的一部分任务,在时间片用完之后,将进程的状态改为等待状态,将进程放到进程队列的尾部,等待cpu的调用
三.关于时间片大小的选择
时间片过小,则进程频繁切换,会造成cpu资源的浪费
时间片过大,则轮转调度算法就退化成了先来先服务算法
二、优先级调度算法:
一、优先级调度算法的基本原理:
优先级进程调度算法,是把处理机分配给就绪队列种优先级最高的进程。即根据优先级来确定排名的算法。
二、根据新的更高优先级进程能否抢占正在执行的进程,可将该调度算法分为:
- 非剥夺式优先级调度算法。当某一个进程正在处理机上运行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在运行的进程继续运行,直到由于其自身的原因而主动让出处理机时(任务完成或等待事件),才把处理机分配给更为重要或紧迫的进程。
- 剥夺式优先级调度算法。当一个进程正在处理机上运行时,若有某个更为重要或紧迫的进程进入就绪队列,则立即暂停正在运行的进程,将处理机分配给更重要或紧迫的进程。
三、根据进程创建后其优先级是否可以改变,可以将进程优先级分为以下两种:
- 静态优先级。优先级是在创建进程时确定的,且在进程的整个运行期间保持不变。确定静态优先级的主要依据有进程类型、进程对资源的要求、用户要求。
- 动态优先级。在进程运行过程中,根据进程情况的变化动态调整优先级。动态调整优先级的主要依据为进程占有CPU时间的长短、就绪进程等待CPU时间的长短。
下面就是笔者使用Java语言对俩种调度算法的实现:
package process; import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner; public class ProcessHandling {
/**
* @author godoforange
* @PCB数据结构
*/
class PCB {
PCB(int id, int priority, int timeuse, int timeround) {
this.id = id;
this.priority = priority;
this.timeuse = timeuse;
this.timeround = timeround;
} int id = 0;// 进程id
int priority = 0;// 优先级
int timeuse = 0;// 需要的运行的时间为
int timeround = 0;// 轮转时间片数为
int cpuuse = 0; @Override
public String toString() {
return "[+]进程ID:" + id + " 优先级为:" + priority + " 需要运行的时间:" + timeuse + " 轮转时间片数为:" + timeround + " 已经占用CPU:"
+ cpuuse;
}
} /**
* @author godoforange
* @优先级比较器
*/
class PriorityComparator implements Comparator<PCB> {
@Override
public int compare(PCB o1, PCB o2) {
if (o1.priority < o2.priority) {
return 1;
} else if (o1.priority > o2.priority) {
return -1;
} else {
return 0;
}
}
}
/**
* @author godoforange
* @param N 总数
* @return 包含了PCB的链表
*/
public List<PCB> createProcess(int N) {
System.out.println("[+]创建进程中。。。");
List<PCB> allPCB = new LinkedList<>();
for (int i = 0; i < N; i++) {
int p = (int) (1 + Math.random() * 10);
int c = (int) (1 + Math.random() * 10);
int b = (int) (1 + Math.random() * 10);
PCB pcb = new PCB(i, p, c, b);
System.out.println("[+]创建第" + i + "个进程,优先级为:" + p + " 需要运行的时间为:" + c + "轮转时间片数为:" + b);
allPCB.add(pcb);
}
return allPCB;
} /**
* @author godoforange
* @轮转法
* @param N 进程数
*/
public void round(int N) {
List<PCB> allPCB = createProcess(N);
System.out.println("[+]轮转法调度执行中");
System.out.println("[+]创建队列");
Queue<PCB> que = new LinkedList<>();
for(PCB pcb : allPCB) {
que.offer(pcb);
}
System.out.println("[+]就绪队列创建完毕");
while(!que.isEmpty()) {
PCB pcb = que.element();
pcb.timeuse--;
pcb.cpuuse++;
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
System.out.println("[+]"+pcb.id + "运行了"+pcb.cpuuse+"次"+"轮转时间片数为"+pcb.timeround);
if (pcb.timeuse < 1) {
System.out.println("[+]"+pcb.id + "运行时间到被移除");
que.remove();
}else if(pcb.cpuuse%pcb.timeround==0) {
que.offer(que.remove());
}
}
} /**
* @author godoforange
* @优先权法
* @param N 进程数
*/
public void priority(int N) {
List<PCB> allPCB = createProcess(N);
Collections.sort(allPCB, new PriorityComparator());
System.out.println("[+]优先权调度执行中");
System.out.println("[+]创建队列:");
for (PCB pcb : allPCB) {
System.out.println(pcb.toString());
}
System.out.println("[+]就绪队列创建完毕");
while (!allPCB.isEmpty()) {
PCB pcb = allPCB.get(0);
pcb.priority -= 3;
pcb.timeuse--;
pcb.cpuuse++;
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
System.out.println("[+]"+pcb.id + "运行了"+pcb.cpuuse+"次"+"优先级为"+pcb.priority);
if (pcb.timeuse < 1) {
System.out.println("[+]进程"+pcb.id + "运行时间到被移除");
allPCB.remove(pcb);
}
Collections.sort(allPCB, new PriorityComparator());
}
System.out.println("[-]优先级调度结束");
} public static void main(String[] args) {
System.out.print("[+]请输入要创建的进程数:");
int N;// 进程数
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
System.out.println("[+]需要创建:" +N+ "个进程");
System.out.print("[+]输入 分别执行优先级调度和轮转法调度 [Y/N]:");
if(sc.nextLine().equals("Y")||sc.nextLine().equals("y")) {
new ProcessHandling().priority(N);
}else{
new ProcessHandling().round(N);
} sc.close();
}
}
运行结果如下:

四、总结
实话来说、这本书其实并不适合让大家真正去理解何为操作系统,因为这里面涉及到的知识很多很多,很多语言十分生涩,即便是有多年经验的开发者也难以对其进行总结。还是希望本科教育能够重视起来,真正的让学生去理解何为操作系统,而非只是生涩的去介绍这些知识。
计算机操作系统处理机调度读后感—–关于进程概念的剖析。从RING3到RING0(32位操作系统)的更多相关文章
- 计算机组成原理--64位CPU装载32位操作系统,它的寻址能力还是4GB吗?
借由这个问题,今天我们就把 32 位 CPU.64 位 CPU.32 位操作系统.64 位操作系统之间的区别与联系彻底搞清楚.对于这个问题,博主也是一知半解了好长时间啊~ 基本概念 32位的CPU与6 ...
- Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现
Python进阶----计算机基础知识(操作系统多道技术),进程概念, 并发概念,并行概念,多进程实现 一丶进程基础知识 什么是程序: 程序就是一堆文件 什么是进程: 进程就是一个正在 ...
- linux:进程概念
Linux进程概念 一.实验介绍1.1 实验内容Linux 中也难免遇到某个程序无响应的情况,可以通过一些命令来帮助我们让系统能够更流畅的运行. 而在此之前,我们需要对进程的基础知识有一定的了解,才能 ...
- 操作系统CPU调度知识点
1.进程基本概念:进程是程序的一次运行. 是系统进程资源分配和调度的基本单位. 2.进程三态:运行状态.就绪状态.堵塞状态.三态转换规则,就绪状态的进程因为调度进程运行状态,运行状态因为时间片用完而进 ...
- Linux进程核心调度器之主调度器schedule--Linux进程的管理与调度(十九)
主调度器 在内核中的许多地方, 如果要将CPU分配给与当前活动进程不同的另一个进程, 都会直接调用主调度器函数schedule, 从系统调用返回后, 内核也会检查当前进程是否设置了重调度标志TLF_N ...
- Linux核心调度器之周期性调度器scheduler_tick--Linux进程的管理与调度(十八)
我们前面提到linux有两种方法激活调度器:核心调度器和 周期调度器 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU 另一种是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要 因 ...
- OS中处理机调度模型和调度算法
OS中处理机调度模型和调度算法 调度层次 1.1. 高级调度(长程调度,作业调度) 功能:依据某种算法.把在外存队列上处于后备队列的那些作业调入内存.以作业为操做对象. 作业:比程序更为广泛的概念,不 ...
- 线程、进程概念与Android系统组件的关系
Android系统是Google公司基于Linux内核开发的开源手机操作系统.通过利用 Linux 内核的优势,Android 系统使用了大量操作系统服务,包括进程管理.内存管理.网络堆栈.驱动程序. ...
- 《Tsinghua os mooc》第15~16讲 处理机调度
第十五讲 处理机调度 进程调度时机 非抢占系统中,当前进程主动放弃CPU时发生调度,分为两种情况: 进程从运行状态切换到等待状态 进程被终结了 可抢占系统中,中断请求被服务例程响应完成时发生调度,也分 ...
随机推荐
- 初识 Hibernate
Hibernate 框架 1.1 什么是框架? 框架是一个提供了可重用的公共结构半成品. 2.1 关于Hibernate Hibernate是数据持久层的一个轻量级框架.数据持久层的框架有很多 ...
- c语言文件打开模式
(转载) 在C语言的文件操作语法中,打开文件文件有以下12种模式,如下图: 打开模式 只可以读 只可以写 读写兼备 文本模式 r w a r+ w+ a+ 二进制模式 rb wb ab rb ...
- PAT 乙级 1005
题目 题目地址:PAT 乙级 1005 题解 本题主要就在于将一个数的一系列计算结果不重复地存储起来并便于检索,考虑到STL中的集合有相似的特性,使用set可以有效地简化代码和运算. 过程如下: (初 ...
- [LUOGU] P1536 村村通
题目描述 某市调查城镇交通状况,得到现有城镇道路统计表.表中列出了每条道路直接连通的城镇.市政府"村村通工程"的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连, ...
- CSS 文本下划线 text-decoration
定义和用法 text-decoration 属性规定添加到文本的修饰. 可能的值 值 描述 none 默认.定义标准的文本. underline 定义文本下的一条线. overline 定义文本上 ...
- Windows Server 2008 R2+SQL Server 2014 R2升级到Windows Server 2016+SQL Server 2016
环境: 操作系统:Windows Server 2008 R2 数据库:SQL Server 2014 因SQL Server 2016可以无域创建AlwaysOn集群,集群只剩下单节点也不会挂掉,故 ...
- 常用模块之configpaser与shutil
configparser模块 定义:configparser翻译为配置解析,即它是用来解析配置文件的 配置文件:用于编写程序的配置信息的文件 配置文件编写格式 配置文件中只允许出现两种类型的数据 se ...
- 我的Python分析成长之路4
一.函数 1.什么是函数?:函数是带名字的代码块,调用函数,只要调用函数名就可以. 2.函数的性质:1.减少重复代码 2.使程序变得可扩展 3.使程序变得易维护 3.编程范示: 1.面向对象编程 ...
- leetcode-3-basic-divide and conquer
解题思路: 因为这个矩阵是有序的,所以从右上角开始查找.这样的话,如果target比matrix[row][col]小,那么就向左查找:如果比它大,就 向下查找.如果相等就找到了,如果碰到边界,就说明 ...
- LeetCode答案(python)
1. 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这 ...