فهرست منبع

lab3框架完成

guanjinquan 1 سال پیش
والد
کامیت
734fa4ec91
7فایلهای تغییر یافته به همراه374 افزوده شده و 9 حذف شده
  1. 23 9
      docs/.vuepress/config.js
  2. 0 0
      docs/Lab/Lab3.md
  3. 67 0
      docs/Lab/Lab3/CFS.md
  4. 80 0
      docs/Lab/Lab3/MLFQ.md
  5. 79 0
      docs/Lab/Lab3/README.md
  6. 68 0
      docs/Lab/Lab3/RR.md
  7. 57 0
      docs/Lab/Lab3/SJF.md

+ 23 - 9
docs/.vuepress/config.js

@@ -11,7 +11,7 @@ module.exports = {
 			items: [
 				{ text: '实验1-熟悉类Linux系统', link: '/Lab/Lab1' },
 				{ text: '实验2-进程创建与进程间通信', link: '/Lab/Lab2' },
-				{ text: '实验3-进程调度算法', link: '/Lab/Lab3' },
+				{ text: '实验3-进程调度算法', link: '/Lab/Lab3/' },
 				{ text: '实验4-存储管理算法', link: '/Lab/Lab4' },
 				{ text: '实验5-文件管理系统', link: '/Lab/Lab5' },
 				{ text: '实验6-网络编程(暂定)', link: '/Lab/Lab6' }
@@ -44,13 +44,27 @@ module.exports = {
 			link: '/about'
 		}
 	],
-	//sidebar: {
-		//'/': [
-			//'',
-			//'Lab-1',
-		//	'Lab-2',
-			//'Lab-3'
-		//]
-    //}
+	sidebar: {
+		'/Lab/Lab3/': [
+			{
+				title: '进程调度',
+				children: [
+					['', '任务说明'],
+					['RR', 'RR调度算法'],
+					['SJF', 'SJF调度算法'],
+					['CFS', 'CFS调度算法'],
+					['MLFQ', 'MLFQ调度算法'],
+				],
+			},
+		],
+		'/Lab/Lab4/': [
+			{
+				title: '存储管理',
+				children: [
+					['', '任务说明'],
+				],
+			},
+		],
+    }
   }
 }

+ 0 - 0
docs/Lab/Lab3.md


+ 67 - 0
docs/Lab/Lab3/CFS.md

@@ -0,0 +1,67 @@
+# 完全公平调度算法
+
+
+
+
+
+## 调度策略与算法原理
+
+​	CFS(Completely Fair Scheduler,完全公平调度器)是一种进程调度策略,最早引入于Linux内核2.6.23版本。CFS的目标是在多核系统中提供公平的CPU时间分配,并以纳秒级的精度进行调度。
+
+基本原则和策略:
+1. 基于虚拟运行时间:CFS使用了一个称为虚拟运行时间(Virtual Runtime)的概念来衡量进程的运行时间。每个进程都被分配一个虚拟运行时间片,进程的调度顺序由虚拟运行时间的大小决定。
+2. 完全公平性:CFS的目标是提供完全公平的调度,即每个进程在一段时间内都能获得相同的CPU时间。这通过动态调整虚拟运行时间来实现。
+3. 红黑树结构:CFS内部使用了一个红黑树数据结构来组织就绪队列,其中每个节点表示一个运行中或就绪的进程。红黑树允许高效的插入、删除和搜索操作。
+4. 虚拟运行时间更新:当一个进程被选中执行时,它的虚拟运行时间会递增,表示它消耗了一定的CPU时间。其他进程的虚拟运行时间会相应减少,以保持公平性。
+5. 完全使用CPU:CFS的目标是尽量让CPU保持100%的利用率,即使只有一个进程在运行,它也会持续消耗CPU时间,而不是空闲状态。
+
+​	CFS调度策略通过动态地调整进程的虚拟运行时间,使得每个进程能够公平地获得CPU时间,从而提供更好的公平性和响应性。它适用于多核系统和服务器环境,能够高效地管理并调度各种类型的任务,确保系统资源的公平分配。
+
+
+
+## 实验步骤
+
+​	接上文,在这里继续完成调度算法的实现
+
+​	你只需要实现一个CFS算法类,然后实现schedule函数,比如下面的方法:
+
+```cpp
+void scheduleCFS(Process processes[], int n) {
+    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> minHeap;
+
+    // 初始化运行队列
+    for (int i = 0; i < n; i++) {
+        minHeap.push(make_pair(processes[i].vruntime, i));
+    }
+
+    int current_time = 0;
+
+    while (!minHeap.empty()) {
+        pair<int, int> minProcess = minHeap.top();
+        minHeap.pop();
+
+        int process_index = minProcess.second;
+        Process currentProcess = processes[process_index];
+
+        cout << "执行进程 " << currentProcess.pid << ",执行时间 " << currentProcess.execution_time << endl;
+
+        current_time += currentProcess.execution_time;
+        currentProcess.vruntime = current_time;
+
+        cout << "进程 " << currentProcess.pid << " 执行完毕,完成时间 " << current_time << endl;
+
+        if (current_time < 100) {
+            minHeap.push(make_pair(currentProcess.vruntime, process_index));
+        }
+    }
+}
+```
+
+
+
+
+
+## 实验结果
+
+
+

+ 80 - 0
docs/Lab/Lab3/MLFQ.md

@@ -0,0 +1,80 @@
+# 多级反馈队列调度算法
+
+
+
+## 调度策略与算法原理 
+
+​	MLFQ(多级反馈队列调度)是一种进程调度策略,它将进程划分为多个优先级队列,并根据优先级队列的特性进行调度。每个队列具有不同的优先级,且优先级随时间变化。MLFQ调度算法的主要思想是给予较高优先级的进程更多的CPU时间,并允许进程在不同的队列之间移动。
+
+基本原则和策略:
+
+1. 多个队列:MLFQ维护多个优先级队列,通常是一个队列数组,每个队列都有不同的优先级。
+2. 优先级调度:较高优先级的队列拥有较短的时间片,即较高的CPU时间分配,以确保高优先级进程能够尽快得到执行。
+3. 时间片轮转:每个队列采用时间片轮转调度策略,当一个进程的时间片用完时,它会被移动到较低优先级的队列中继续执行。
+4. 优先级提升:为了避免饥饿情况,MLFQ允许进程在队列之间移动。例如,如果一个进程在较低优先级队列中等待了一段时间,它可以被提升到较高优先级队列中以获得更多的CPU时间。
+5. 公平性控制:为了避免长时间运行的进程占用所有CPU时间,MLFQ通常采用一些机制来控制进程的优先级提升速度或降低速度,以实现公平性。
+
+​	MLFQ的设计可以根据具体需求进行调整和改进,例如,可以调整队列数量、时间片长度、优先级提升规则等来适应不同的系统环境和应用场景。该调度策略在实践中常用于操作系统中,以平衡系统的吞吐量和响应时间,同时为不同类型的进程提供适当的执行机会。
+
+
+
+
+
+## 实验步骤
+
+​	接上文,在这里继续完成调度算法的实现:
+
+​	你只需要实现一个MLFQ算法类,然后实现schedule函数,比如下面的方法:
+
+```cpp
+void schedule(Process processes[], int n, vector<int> time_quantums) {
+    int num_queues = time_quantums.size();
+    vector<queue<Process>> readyQueues(num_queues); // 多个优先级的就绪队列
+
+    // 将所有进程按照优先级加入对应的就绪队列
+    for (int i = 0; i < n; i++) {
+        int priority = processes[i].priority;
+        readyQueues[priority].push(processes[i]);
+    }
+
+    for (int i = 0; i < num_queues; i++) {
+        int time_quantum = time_quantums[i];
+
+        while (!readyQueues[i].empty()) {
+            Process currentProcess = readyQueues[i].front();
+            readyQueues[i].pop();
+
+            // 执行一个时间片
+            if (currentProcess.remaining_time > time_quantum) {
+                cout << "执行进程 " << currentProcess.pid << ",执行时间片 " << time_quantum << endl;
+                currentProcess.remaining_time -= time_quantum;
+
+                // 降低优先级并将进程重新加入就绪队列
+                currentProcess.priority++;
+                if (currentProcess.priority < num_queues) {
+                    readyQueues[currentProcess.priority].push(currentProcess);
+                } else {
+                    readyQueues[num_queues - 1].push(currentProcess);
+                }
+            } else {
+                cout << "执行进程 " << currentProcess.pid << ",执行时间片 " << currentProcess.remaining_time << endl;
+                currentProcess.remaining_time = 0;
+            }
+
+            // 进程执行完毕
+            if (currentProcess.remaining_time == 0) {
+                cout << "进程 " << currentProcess.pid << " 执行完毕" << endl;
+            }
+        }
+    }
+}
+```
+
+
+
+
+
+## 实验结果
+
+
+

+ 79 - 0
docs/Lab/Lab3/README.md

@@ -0,0 +1,79 @@
+# 实验三 - 进程调度
+
+
+
+## 前言
+
+(1)为什么要引入进程调度?
+
+(2)主要针对单核处理机的调度算法做研究
+
+(3)历史发展脉络
+
+(4)进程调度的性能指标是什么
+
+(5)进程切换
+
+(6)进程调度的实现
+
+
+
+## 一、实验目的 
+
+​	操作系统的内核中实现的调度器比较复杂,其本质组成就是3大模块:就绪队列、调度器、分配器。
+
+​	在本次实验中,三者之中的就绪队列将会作为参数提供给你,你需要实现的是调度器,然后由系统本身实现的分配器调用你事先的调度器,以检验算法的正确性。
+
+​	实现调度器的最困难的地方在于实现调度算法(抛开提高性能、降低耦合性等事实不谈),请你结合实验教程完成调度算法的实现,并按照规范实现程序接口,以保证整个系统能够运行。
+
+
+
+
+
+## 二、实验步骤
+
+### 1. 进程控制块(PCB)结构
+
+​	进程控制块(PCB)是操作系统中用于管理和描述进程的数据结构。它存储了一个进程的相关信息,包括进程状态、程序计数器、寄存器值、内存分配信息、打开的文件列表等。
+
+​	在本次实验中,我们已经帮你设计好了PCB,你需要理解PCB中的每个变量的作用以及意义,在此基础上实现调度算法,并通过实验数据测试。
+
+​	下面是我们规定的PCB结构体:
+
+```cpp
+struct PCB {
+    int pid;                 // 进程ID
+    string name;             // 进程名称
+    string state;            // 进程状态 (一般来说 就绪队列里面的进程都是Ready状态)
+    int priority;            // 进程优先级
+    int burst_time;          // 进程的执行时间
+    int remain_time;         // 剩余执行时间
+    int arrive_time;         // 进程到达时间
+};
+```
+
+​	该结构体具有上述变量。对于不同的编程语言,变量名称都与上面的代码一致。
+
+
+
+### 2. 调度策略
+
+​	在这一步,你需要根据不同的调度策略设计响应的调度算法,调度策略有以下几种:
+
+- FCFS(First Come First Serve)
+
+- RR(Round-Robin,轮转调度)
+
+- SJF(Shortest Job First,最短作业优先)
+
+- MLFQ(多级反馈队列调度)
+
+- CFS(Completely Fair Scheduler,完全公平调度器)
+
+​	请跳转到响应的实验教程中继续完成实验。
+
+
+
+
+
+## 课外资料

+ 68 - 0
docs/Lab/Lab3/RR.md

@@ -0,0 +1,68 @@
+# 时间片轮转算法
+
+
+
+## 调度策略与算法原理
+
+​	RR(Round-Robin,轮转调度)是一种常见的进程调度策略,它以时间片(固定时间段)为单位,依次为每个进程分配CPU时间。每个进程在就绪队列中按照到达顺序排队,并且每个进程都能够在一个时间片内获得一定的CPU执行时间,然后被放回队列尾部继续等待执行。
+
+基本原则和策略:
+1. 时间片:RR调度策略将CPU时间划分为固定的时间片。当一个进程获得CPU执行时,它被允许执行一个时间片的长度,然后被放回队列等待下一次执行。
+2. 队列调度:进程按照到达顺序排队在就绪队列中,每个进程依次获得执行机会。当一个进程的时间片用完后,==它被放回队列的尾部==,下一个进程开始执行。
+3. 循环执行:RR调度策略按照循环的方式执行进程,每个进程都能获得一定的CPU时间,以确保公平性。
+4. 非抢占式调度:一个进程在执行过程中不会被强制中断或抢占,直到它的时间片用完。
+
+​	RR调度策略具有公平性和响应性,因为每个进程都能获得一定的执行时间,并且长时间运行的进程不会占用所有的CPU时间。然而,如果时间片过小,会导致频繁的上下文切换,增加系统开销;如果时间片过大,会影响系统对紧急任务的响应时间。
+
+​	RR调度策略在操作系统中被广泛应用,尤其是在分时系统和交互式系统中,它能够合理分配CPU时间,提供良好的用户体验。
+
+
+
+
+
+## 实验步骤
+
+​	接上文,在这里继续完成调度算法的实现
+
+​	你只需要实现一个RR算法类,然后实现schedule函数,比如下面的方法:
+
+```cpp
+void schedule(Process processes[], int n, int time_slice) {
+    queue<Process> readyQueue;
+
+    // 将所有进程加入就绪队列
+    for (int i = 0; i < n; i++) {
+        readyQueue.push(processes[i]);
+    }
+
+    while (!readyQueue.empty()) {
+        Process currentProcess = readyQueue.front();
+        readyQueue.pop();
+
+        // 执行一个时间片
+        if (currentProcess.remaining_time > time_slice) {
+            cout << "执行进程 " << currentProcess.pid << ",执行时间片 " << time_slice << endl;
+            currentProcess.remaining_time -= time_slice;
+        } else {
+            cout << "执行进程 " << currentProcess.pid << ",执行时间片 " << currentProcess.remaining_time << endl;
+            currentProcess.remaining_time = 0;
+        }
+
+        // 将已执行完的进程重新加入就绪队列
+        if (currentProcess.remaining_time > 0) {
+            readyQueue.push(currentProcess);
+        }
+    }
+}
+```
+
+
+
+
+
+## 实验结果
+
+
+
+
+

+ 57 - 0
docs/Lab/Lab3/SJF.md

@@ -0,0 +1,57 @@
+# 非抢占式最短作业优先算法
+
+
+
+## 调度策略与算法原理
+
+​	SJF(Shortest Job First,最短作业优先)是一种进程调度策略,它选择执行时间最短的进程来优先执行。在SJF调度策略下,操作系统会根据进程的执行时间长度来决定调度顺序,短作业将被优先执行。
+
+基本原则和策略:
+1. 作业长度:SJF调度策略假设我们可以预测每个进程的执行时间。因此,每个进程都被分配了一个执行时间长度。
+2. 最短作业优先:在就绪队列中,选择具有最短执行时间的进程来执行。这意味着进程的执行时间越短,越容易获得CPU的执行机会。
+3. 非抢占式调度:一旦进程开始执行,它将一直运行到完成,除非它自愿释放CPU或阻塞。
+4. 先来先服务:当多个进程具有相同的执行时间时,采用先到先服务(FIFO)原则,即按照进程到达的顺序来决定执行顺序。
+
+​	SJF调度策略旨在减少平均等待时间,因为短作业往往能够更快地完成并释放CPU资源,从而提高系统的吞吐量和响应时间。然而,SJF调度策略需要提前了解每个进程的执行时间,而在实际情况中,通常无法准确预测进程的执行时间。因此,SJF调度策略往往用作一种参考,而非实际应用的主要调度算法。	
+
+​	扩展:抢占式最短作业优先算法是:最短完成时间优先(Shortest Time to Complet First)调度策略。
+
+
+
+
+
+## 实验步骤
+
+​	接上文,在这里继续完成调度算法的实现
+
+​	你只需要实现一个SJF算法类,然后实现schedule函数,比如下面的方法:
+
+```cpp
+bool compareByBurstTime(const Process& p1, const Process& p2) {
+    return p1.burst_time < p2.burst_time;
+}
+
+void schedule(Process processes[], int n) {
+    // 按照执行时间排序进程
+    sort(processes, processes + n, compareByBurstTime);
+
+    int current_time = 0;
+
+    for (int i = 0; i < n; i++) {
+        Process currentProcess = processes[i];
+
+        cout << "执行进程 " << currentProcess.pid << ",执行时间 " << currentProcess.burst_time << endl;
+
+        current_time += currentProcess.burst_time;
+
+        cout << "进程 " << currentProcess.pid << " 执行完毕,完成时间 " << current_time << endl;
+    }
+}
+```
+
+
+
+## 实验结果
+
+
+