├── 页面置换算法(测试) ├── Python │ └── mx │ │ ├── algorithm │ │ ├── __init__.py │ │ └── LRU.py │ │ └── sample │ │ ├── __init__.py │ │ └── LRUSample.py ├── Golang │ ├── go.mod │ ├── main.go │ └── lru │ │ └── lru.go ├── Java │ └── com │ │ └── dhx │ │ ├── sample │ │ └── LRUSample.java │ │ └── algorithms │ │ └── lru │ │ ├── Node.java │ │ ├── DoubleList.java │ │ └── LRUCache.java └── README.md ├── 进程调度算法 ├── golang │ ├── go.mod │ ├── main.go │ ├── model │ │ └── Process.go │ └── algorithms │ │ ├── FCFS.go │ │ └── Priority.go ├── Python │ ├── example │ │ ├── SJFExample.py │ │ ├── PSExample.py │ │ ├── SRTFExample.py │ │ ├── RRExample.py │ │ ├── FCFSExample.py │ │ └── MLFQExample.py │ ├── FCFS.py │ ├── model.py │ ├── SJF.py │ ├── RR.py │ ├── SRTF.py │ ├── MLFQ.py │ └── PS.py ├── C++ │ ├── samlpe │ │ ├── FCFSexample.cpp │ │ ├── RRexample.cpp │ │ ├── SRTFexample.cpp │ │ ├── PSexample.cpp │ │ ├── SLFexample.cpp │ │ └── MLFQexample.cpp │ ├── model │ │ └── PCB.h │ └── algorithms │ │ ├── SRTF.cpp │ │ └── PS.cpp ├── Java │ └── com │ │ └── dhx │ │ ├── sample │ │ ├── FCFSSample.java │ │ ├── SJFSample.java │ │ ├── PrioritySample.java │ │ ├── MLFQSample.java │ │ └── HRRNSample.java │ │ ├── model │ │ └── Process.java │ │ └── algorithms │ │ ├── FCFS.java │ │ ├── SJF.java │ │ ├── Priority.java │ │ └── MLFQ.java └── README.md ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── discussion.md │ ├── question.md │ └── bug_report.md ├── 页面置换算法 ├── C++ │ ├── sample │ │ ├── FIFOExample.cpp │ │ ├── LFUExample.cpp │ │ ├── LRUExample.cpp │ │ ├── ClockUpdateExample.cpp │ │ └── ClockSimpleExample.cpp │ ├── model │ │ ├── CacheNode.h │ │ └── Mem.h │ └── algorithms │ │ ├── ClockUpdate.cpp │ │ ├── ClockSimple.cpp │ │ ├── LFU.cpp │ │ ├── FIFO.cpp │ │ └── LRU.cpp ├── Java │ └── com │ │ └── dhx │ │ ├── model │ │ ├── Constant.java │ │ ├── Element.java │ │ └── DoubleLinkedList.java │ │ ├── sample │ │ ├── NRUExample.java │ │ ├── LRUExample.java │ │ ├── LFUExample.java │ │ └── FIFOExample.java │ │ └── algorithms │ │ └── fifo │ │ └── FIFO.java └── README.md ├── 磁盘调度算法 ├── Python │ ├── algorithm │ │ ├── FCFS.py │ │ ├── SSTF.py │ │ ├── SCAN.py │ │ └── CSCAN.py │ └── sample │ │ └── Sample.py ├── Java │ ├── algorithms │ │ ├── FCFS.java │ │ ├── CSCAN.java │ │ ├── SSTF.java │ │ └── SCAN.java │ ├── sample │ │ └── Example.java │ └── util │ │ └── TestUtil.java ├── C++ │ └── algorithms │ │ ├── LIFO.cpp │ │ ├── FCFS.cpp │ │ ├── C-SCAN.cpp │ │ ├── SSTF.cpp │ │ └── SCAN.cpp └── README.md ├── 动态分区匹配算法 ├── Java │ └── com │ │ └── os │ │ └── dynamicmatching │ │ ├── model │ │ ├── DMConstant.java │ │ ├── Frame.java │ │ ├── FramePartitionNode.java │ │ └── Process.java │ │ ├── util │ │ ├── TimeUtil.java │ │ └── AlgorithmUtil.java │ │ ├── sample │ │ ├── QFExample.java │ │ ├── FFExample.java │ │ └── NFExample.java │ │ └── algorithms │ │ ├── WF.java │ │ └── FF.java ├── README.md ├── python │ ├── algorithms │ │ ├── QuickFit.py │ │ ├── WorstFit.py │ │ ├── BestFit.py │ │ └── FirstFit.py │ └── sample │ │ └── Sample.py └── Cpp │ ├── FF.cpp │ ├── WF.cpp │ ├── BF.cpp │ └── QF.cpp ├── LICENSE ├── README.md └── .gitignore /页面置换算法(测试)/Python/mx/algorithm/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Python/mx/sample/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /进程调度算法/golang/go.mod: -------------------------------------------------------------------------------- 1 | module golang 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Golang/go.mod: -------------------------------------------------------------------------------- 1 | module golang 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Python/mx/sample/LRUSample.py: -------------------------------------------------------------------------------- 1 | from algorithm import LRU -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md linguist-vendored=false 2 | *.md linguist-generated=false 3 | *.md linguist-documentation=false 4 | *.md linguist-detectable=true 5 | -------------------------------------------------------------------------------- /进程调度算法/Python/example/SJFExample.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 SJF测试 2 | 3 | import SJF 4 | if __name__ == '__main__': 5 | SJF.inPcb() # 输入五个进程信息 6 | SJF.sjf() # 输出结果 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/discussion.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Discussion 3 | about: Start a discussion for Implementation-of-os-classical-algorithm 4 | title: '' 5 | labels: type/discussion 6 | assignees: '' 7 | --- 8 | 9 | ## Describe your thoughts here -------------------------------------------------------------------------------- /页面置换算法/C++/sample/FIFOExample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 12494 on 2023/5/14. 3 | // 4 | 5 | #include "../algorithms/FIFO.cpp" 6 | int main() { 7 | system("chcp 65001"); 8 | init(); 9 | run(); 10 | print(); 11 | return 0; 12 | } 13 | //7 0 1 2 0 3 0 4 2 3 0 3 2 -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/FCFSexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/7. 3 | // 4 | #include "../algorithms/FCFS.cpp" 5 | #include 6 | /* 7 | A 3 2 8 | B 2 3 9 | C 2 4 10 | */ 11 | 12 | int main() { 13 | system("chcp 65001"); 14 | FCFS(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /进程调度算法/Python/example/PSExample.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 PS算法测试 2 | 3 | import PS 4 | 5 | 6 | if __name__ == "__main__": 7 | # 创建PS对象 8 | ps = PS.PS() 9 | 10 | # 初始化进程 11 | ps.init() 12 | 13 | # 运行进程调度 14 | ps.run() 15 | 16 | # 打印最终结果 17 | ps.print_result() -------------------------------------------------------------------------------- /进程调度算法/Python/example/SRTFExample.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 SRTF算法测试 2 | 3 | 4 | import SRTF 5 | 6 | processes = [ 7 | SRTF.Process(1, 0, 8), 8 | SRTF.Process(2, 1, 4), 9 | SRTF.Process(3, 2, 9), 10 | SRTF.Process(4, 3, 5), 11 | SRTF.Process(5, 4, 2) 12 | ] 13 | SRTF.SRTF(processes) 14 | -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/RRexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/7. 3 | // 4 | 5 | //例子 6 | /* 7 | A 3 2 8 | B 2 3 9 | C 2 4 10 | */ 11 | #include "../algorithms/RR.cpp" 12 | #include 13 | int main(){ 14 | system("chcp 65001"); 15 | init(); 16 | RRArithmetic(); 17 | output(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/SRTFexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/14. 3 | // 4 | 5 | #include "../algorithms/SRTF.cpp" 6 | 7 | // 主函数,测试SrserviceTimeF调度算法 8 | int main() { 9 | system("chcp 65001"); 10 | init(); 11 | // 调用SrserviceTimeF调度算法函数 12 | Run(); 13 | Print(); 14 | 15 | // 返回0表示程序正常结束 16 | return 0; 17 | } -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/PSexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 12494 on 2023/5/9. 3 | // 4 | 5 | #include "../algorithms/PS.cpp" 6 | #include 7 | //example 8 | /* 9 | A 4 2 4 10 | B 5 1 5 11 | C 0 5 3 12 | D 1 3 5 13 | E 2 1 3 14 | F 3 1 4 15 | G 4 2 2 16 | */ 17 | int main() 18 | { 19 | system("chcp 65001"); 20 | init(); 21 | run(); 22 | } -------------------------------------------------------------------------------- /磁盘调度算法/Python/algorithm/FCFS.py: -------------------------------------------------------------------------------- 1 | import random 2 | import copy 3 | TRACK_MAX_COUNT = 100 # 磁道的总数 4 | TRACK_REQUEST_COUNT = 10 # 请求访问的磁道数量 5 | TRACK_START = 50 6 | SCAN_DIRECTION = 1 # 1表示向磁道号增加的方向扫描,0表示向磁道号减小的方向 7 | N_STEPSCAN = 4 # 表示请求队列被划分为长度为 N 的子队列 8 | def FCFS(track_request): 9 | queue_FCFS = track_request.copy() 10 | queue_FCFS.insert(0, TRACK_START) 11 | return queue_FCFS 12 | 13 | 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about Implementation-of-os-classical-algorithm 4 | title: '' 5 | labels: type/question 6 | assignees: '' 7 | 8 | --- 9 | 10 | - [ ] I have searched the [issues](https://github.com/adorabled4/Implementation-of-os-classical-algorithm/issues) of this repository and believe that this is not a duplicate. 11 | 12 | ## Ask your question here 13 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/model/DMConstant.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.model; 2 | 3 | /** 4 | * @author adorabled4 5 | * @className DMConstant 存储常量 6 | * @date : 2023/05/13/ 15:37 7 | **/ 8 | public class DMConstant { 9 | 10 | public static final Integer DEFAULT_FRAME_SIZE=500; 11 | 12 | public static final Integer FREE=0; 13 | 14 | public static final Integer USED=1; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /进程调度算法/Python/example/RRExample.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 RR算法测试 2 | 3 | import RR 4 | 5 | 6 | def main(): 7 | while True: 8 | p_num = input("请输入进程数:") 9 | if p_num.isdigit(): 10 | p_num = int(p_num) 11 | p_dict = RR.createP(p_num) 12 | RR.lunzhuanP(p_dict, p_num) 13 | 14 | else: 15 | print("输入的不是有效数字") 16 | 17 | 18 | if __name__ == "__main__": 19 | main() 20 | -------------------------------------------------------------------------------- /页面置换算法/C++/model/CacheNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/6. 3 | // 4 | 5 | #ifndef IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 6 | #define IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 7 | class CacheNode{ 8 | public: 9 | int key; 10 | int value; 11 | CacheNode *pre, *next;//节点的前驱、后继指针 12 | 13 | CacheNode(int key, int value) : key(key), value(value) {} 14 | 15 | }; 16 | 17 | 18 | #endif //IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 19 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | /** 7 | * @author adorabled4 8 | * @className TimeUtil 9 | * @date : 2023/05/13/ 16:45 10 | **/ 11 | public class TimeUtil { 12 | public static String getCurrentTime(){ 13 | //2023-5-13 16:45:55 14 | return new SimpleDateFormat("yyyy-MM--dd hh:mm:ss").format(new Date()) + " "; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /页面置换算法/C++/model/Mem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/8. 3 | // 4 | #ifndef IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 5 | #define IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | class Mem { //内存 12 | public: 13 | int pageNum; //页面号 14 | int visit; //访问位 15 | int modify;//修改位 16 | }; 17 | 18 | #endif //IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_CACHENODE_H 19 | -------------------------------------------------------------------------------- /进程调度算法/Python/FCFS.py: -------------------------------------------------------------------------------- 1 | 2 | def fcfs(list1): # 先来先服务 3 | time = 0 4 | while 1: 5 | print("time:", time) 6 | if time >= list1[0].arr_time: 7 | list1[0].running() 8 | list1[0].Output() 9 | if list1[0].all_time == 0: 10 | print("进程" + list1[0].pid + " 执行完毕,周转时间:" + str(time - list1[0].arr_time + 1) + "\n") 11 | list1.remove(list1[0]) 12 | time += 1 13 | if not list1: 14 | break 15 | 16 | 17 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Golang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "golang/lru" 6 | ) 7 | 8 | func main() { 9 | LruTest() 10 | } 11 | func LruTest() { 12 | cache := lru.Constructor(3) 13 | cache.Put(1, 1) 14 | cache.Put(2, 2) 15 | cache.Put(3, 3) 16 | fmt.Print("初始化lru队列 : ") 17 | cache.PrintList() // 打印初始的lru队列 18 | cache.Put(4, 4) // 添加 node4 ,由于容量有限, node1被移除 19 | fmt.Print("添加node(4,4) : ") 20 | cache.PrintList() 21 | fmt.Print("调用node(2,2) : ") 22 | cache.Get(2) // 再次调用, node2重新回到最新的位置 23 | cache.PrintList() 24 | } 25 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/model/Constant.java: -------------------------------------------------------------------------------- 1 | package com.dhx.model; 2 | 3 | /** 4 | * @author adorabled4 5 | * @className Constant 6 | * @date : 2023/05/06/ 10:00 7 | **/ 8 | public class Constant { 9 | 10 | /** 11 | * 初始化所有的页面数 12 | */ 13 | public static final Element[]elements; 14 | 15 | static { 16 | elements=new Element[11]; 17 | // 由于映射的关系是使用element的key , 因此在数组赋值的时候需要提前设置一个0 element进行占位操作 18 | for (int i = 0; i <= 10; i++) { 19 | elements[i]=new Element(i,10000+i); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/SLFexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/8. 3 | // 4 | /* 5 | A 3 2 6 | B 2 3 7 | C 2 4 8 | */ 9 | #include "../algorithms/SLF.cpp" 10 | int main() 11 | { 12 | system("chcp 65001"); 13 | // 初始化就绪队列 14 | init(); 15 | // 按到达时间从小到大排序 16 | sort(SLFobject.SLFarray + 1, SLFobject.SLFarray + 1 + SLFobject.n, 17 | [](const PCB & x, const PCB & y) 18 | { return x.arriveTime < y.arriveTime; }); 19 | // 显示进程初始状态 20 | show(); 21 | // 实际运行阶段 22 | run(); 23 | // 显示各进程的周转时间和带权周转时间 24 | display(); 25 | system("pause"); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /进程调度算法/C++/samlpe/MLFQexample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 12494 on 2023/5/13. 3 | // 4 | 5 | /* 6 | * 输入:进程ID,所需要的CPU资源,所需要的IO资源,先执行CPU or IO 7 | * 第一次执行是指定先执行cpu或者io,此后该程序cpu,io交替执行 8 | * 若在进程执行 cpu时候 时间片到,降级,最低级不再降 9 | * 若在进程执行 io时候 时间片到,升级,最高级不再升 10 | * 若程序执行完CPU或者IO后 时间片未到,程序执行剩余的IO或者CPU 11 | * 最终在第一级队列结束的是IO密集型,不管输入CPU,IO是多少,IO多则升级,CPU多则降级 12 | * 限时输入,若不输入程序过几秒自动运行(秒数可以自己设置) 13 | * 随时中断,进程运行过程中可以添加新进程 14 | * 有抢占,添加的新进程进入第一队列,并且立马执行 15 | * 第一级队列不会发生抢占,但仍然可以添加新进程,进程排到第一级队列尾 16 | * 被抢占的进程返回进程所在队列的队尾等待执行 17 | * 被抢占的进程在轮到该进程后继续上次剩余的时间片 18 | * 可选择是否使用RunIO_CPU() 函数,该函数是在运行IO时记录时间片,并寻找最高优先级的进程运行CPU,达到模拟有进程在运行IO的时候,同时有别的进程在运行CPU 19 | */ 20 | 21 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Java/com/dhx/sample/LRUSample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.lru.LRUCache; 4 | 5 | /** 6 | * @author dhx_ 7 | * @className LruSample 8 | * @date : 2023/02/17/ 12:41 9 | **/ 10 | public class LRUSample { 11 | 12 | public static void main(String[] args) { 13 | LRUCache cache = new LRUCache(3); // 设置lru序列的容量为3 14 | // 添加三个前置数据 , 保证此时lru序列已满 15 | cache.put(1, 1); 16 | cache.put(2, 2); 17 | cache.put(3, 3); 18 | System.out.println("the first Node :"+cache.get(1)); 19 | cache.put(4, 3); 20 | System.out.println(cache); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Java/com/dhx/algorithms/lru/Node.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms.lru; 2 | 3 | /** 4 | * @author dhx_ 5 | * @className Node 6 | * @date : 2023/02/17/ 19:28 7 | **/ 8 | public class Node { 9 | 10 | /** 11 | * K V 12 | */ 13 | public int key, val; 14 | 15 | /** 16 | * 下一个节点 17 | */ 18 | public Node next; 19 | 20 | /** 21 | * 前一个节点 22 | */ 23 | public Node pre; 24 | 25 | public Node(int k, int v) { 26 | this.key = k; 27 | this.val = v; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "Node{" + 33 | "key=" + key + 34 | ", val=" + val + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /进程调度算法/Python/example/FCFSExample.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import FCFS 4 | import model 5 | 6 | 7 | def init(num): # 初始化进程,生成四个进程并按到达时间将它们放入列表list1 8 | list1 = [] 9 | for i in range(num): 10 | list1.append(model.Process(str(i), random.randint(1, 10), random.randint(10, 15), 11 | random.randint(1, 10), 0, random.randint(5, 10), random.randint(1, 10), "Ready")) 12 | for i in range(len(list1) - 1): 13 | for j in range(i + 1, len(list1)): 14 | if list1[i].arr_time > list1[j].arr_time: 15 | list1[i], list1[j] = list1[j], list1[i] 16 | return list1 17 | 18 | if __name__ == "__main__": 19 | list1 = init(4) 20 | for i in list1: 21 | i.Output() 22 | FCFS.fcfs(list1) -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/model/Element.java: -------------------------------------------------------------------------------- 1 | package com.dhx.model; 2 | 3 | /** 4 | * @author dhx_ 5 | * @className Node 6 | * @date : 2023-5-5 17:40:16 7 | **/ 8 | public class Element { 9 | 10 | /** 11 | * K V 12 | */ 13 | public int key, val; 14 | 15 | /** 16 | * 下一个节点 17 | */ 18 | public Element next; 19 | 20 | /** 21 | * 前一个节点 22 | */ 23 | public Element pre; 24 | 25 | public Element(int k, int v) { 26 | this.key = k; 27 | this.val = v; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "\u001B[34m\u001B[1mElement \u001B[0m{" + 33 | "key=" + key + 34 | ", val=" + val + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Python/mx/algorithm/LRU.py: -------------------------------------------------------------------------------- 1 | """LRU淘汰算法: 2 | 1。如果此数据已经被缓存到链表中,遍历得到数据节点,将其从原位置删除,然后再插入链表头部 3 | 2。如果数据没有再缓存链表中:缓存未满, 则直接加入头部 4 | 缓存已满, 则先删除尾节点,再将新的节点插入到链表 5 | 6 | """ 7 | data_list = [] # 定义列表 8 | list_num = 5 # 确定缓存区大小. 9 | # 进行算法实现 10 | def LRUP(num): 11 | if num in data_list: #如果数据已经存在缓存区,把它放在链表头部 12 | data_list.remove(num) 13 | data_list.insert(0,num) 14 | else: 15 | if len(data_list) < list_num: #如果所输入数据没有被加载到缓存且缓存没有满,直接把数据添加到链表头部 16 | data_list.insert(0, num) 17 | else: 18 | data_list.pop(-1) #如果所输入数据没有被加载到内存且链表已满,把列表尾部删除,把新数据添加到链表头部 19 | data_list.insert(0, num) 20 | print(data_list) 21 | LRUP(1) 22 | LRUP(2) 23 | LRUP(3) 24 | LRUP(4) 25 | LRUP(5) 26 | LRUP(3) 27 | LRUP(7) -------------------------------------------------------------------------------- /磁盘调度算法/Python/algorithm/SSTF.py: -------------------------------------------------------------------------------- 1 | from FCFS import * 2 | def findNearest(current, track_request, visited): 3 | minDis = TRACK_MAX_COUNT 4 | minIndex = -1 5 | for i in range(len(track_request)): 6 | if visited[i] == False: 7 | dis = abs(current - track_request[i]) 8 | if dis < minDis: 9 | minDis = dis 10 | minIndex = i 11 | visited[minIndex] = True 12 | return minIndex, minDis 13 | 14 | 15 | def SSTF(track_request): 16 | visited = [False] * TRACK_REQUEST_COUNT 17 | queue_FCFS = [] 18 | current = TRACK_START # 起始的磁道 19 | for i in range(len(track_request) + 1): 20 | index, dis = findNearest(current, track_request, visited) 21 | queue_FCFS.append(current) 22 | current = track_request[index] 23 | return queue_FCFS 24 | 25 | queue_SCAN.append(TRACK_START) 26 | current = TRACK_START 27 | 28 | -------------------------------------------------------------------------------- /磁盘调度算法/Python/algorithm/SCAN.py: -------------------------------------------------------------------------------- 1 | from FCFS import * 2 | def SCAN(track_request): 3 | global SCAN_DIRECTION 4 | queue_SCAN = [] 5 | 6 | track_request_copy = copy.deepcopy(track_request) 7 | track_request_copy.sort() 8 | while track_request_copy.__len__() != 0: 9 | if SCAN_DIRECTION == 1: 10 | for track in track_request_copy.copy(): 11 | if TRACK_START <= track: 12 | queue_SCAN.append(track) 13 | track_request_copy.remove(track) 14 | SCAN_DIRECTION = 0 15 | 16 | if SCAN_DIRECTION == 0: 17 | track_request_copy.reverse() 18 | for track in track_request_copy.copy(): 19 | if TRACK_START >= track: 20 | queue_SCAN.append(track) 21 | current = track 22 | track_request_copy.remove(track) 23 | SCAN_DIRECTION = 1 24 | return queue_SCAN 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug in Implementation-of-os-classical-algorithm 4 | title: '' 5 | labels: type/bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | - [ ] I have searched the [issues](https://github.com/adorabled4/Implementation-of-os-classical-algorithm/issues) of this repository and believe that this is not a duplicate. 11 | 12 | ### Environment 13 | 14 | * Operating System version: xxx 15 | * Java version: xxx 16 | * Python version: xxx 17 | * Golang version: xxx 18 | * Cpp version: xxx 19 | 20 | ### Steps to reproduce this issue 21 | 22 | 1. xxx 23 | 2. xxx 24 | 25 | Pls. provide [GitHub address] to reproduce this issue. 26 | 27 | ### Where the bug located 28 | 29 | 1. xxx(Algorithm) 30 | 2. xxx(Programming Language) 31 | 32 | 33 | ### Expected Behavior 34 | 35 | 36 | 37 | ### Actual Behavior 38 | 39 | 40 | 41 | If there is an exception, please attach the exception trace: 42 | 43 | ``` 44 | Just put your stack trace here! 45 | ``` 46 | -------------------------------------------------------------------------------- /磁盘调度算法/Python/sample/Sample.py: -------------------------------------------------------------------------------- 1 | 2 | from CSCAN import * 3 | from SSTF import * 4 | from SCAN import * 5 | from FCFS import * 6 | def caculate(queue): 7 | print('访问的磁道序列为: ', end='') 8 | print(queue) 9 | sum_gap = sum([(abs(queue[i] - queue[i - 1])) for i in range(1, len(queue))]) 10 | print('移动的磁道数为:%d' % sum_gap) 11 | print('平均移动的磁道数为:%.2f' % (sum_gap / TRACK_REQUEST_COUNT)) 12 | print("") 13 | if __name__ == '__main__': 14 | track_request = [None] * TRACK_REQUEST_COUNT 15 | for i1 in range(TRACK_REQUEST_COUNT): 16 | track_request[i1] = random.randint(0, TRACK_MAX_COUNT) 17 | 18 | print('每次生成的磁道序列是随机的,对于不同的序列算法的算法的性能是不一样的,' 19 | '通过多次比较观察结果,SSTF是算法中移动的磁道数最少的') 20 | 21 | print("TRACK SEQUECE: ") 22 | print(track_request) 23 | print('') 24 | 25 | print("FCFS: ") 26 | caculate(FCFS(track_request)) 27 | 28 | print("SSTF: ") 29 | caculate(SSTF(track_request)) 30 | 31 | print("SCAN: ") 32 | caculate(SCAN(track_request)) 33 | 34 | print("CSCAN: ") 35 | caculate(CSCAN(track_request)) -------------------------------------------------------------------------------- /进程调度算法/golang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "golang/algorithms" 6 | "golang/model" 7 | "math/rand" 8 | "time" 9 | ) 10 | 11 | // 继承调度类 12 | type Dispatch interface { 13 | Add(process model.Process) 14 | Start() 15 | } 16 | 17 | var basePid = 1000 18 | 19 | func main() { 20 | PrioritySample() 21 | } 22 | 23 | func PrioritySample() { 24 | var prio Dispatch = algorithms.PriorityConstructor(5) 25 | go addProcess(prio, 5, 6, 4) // 开启新的线程 26 | prio.Start() 27 | } 28 | 29 | func FCFSSample() { 30 | var fcfs Dispatch = algorithms.FcFsConstructor(5) 31 | go addProcess(fcfs, 5, 6, 4) // 开启新的线程 32 | fcfs.Start() 33 | } 34 | 35 | // 添加进程 36 | func addProcess(dispatch Dispatch, size, maxRunTime, maxSleepTime int) { 37 | for i := 0; i < size; i++ { 38 | runtime := rand.Int()%5 + 2 39 | order := rand.Int()%5 + 1 40 | process := model.ConstructorOrder(basePid+i, runtime, order) 41 | if dispatch == nil { 42 | fmt.Println("fcfs is nil") 43 | i = i - 1 44 | } else { 45 | dispatch.Add(process) 46 | } 47 | time.Sleep(time.Duration(rand.Intn(maxSleepTime)) * time.Second) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 dhx_ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/model/Frame.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.model; 2 | 3 | 4 | /** 5 | * @author adorabled4 6 | * @className Frame 模拟帧 7 | * @date : 2023/05/13/ 15:33 8 | **/ 9 | public class Frame { 10 | 11 | /** 12 | * 当前状态 13 | */ 14 | private int status; 15 | 16 | /** 17 | * 帧号 18 | */ 19 | private int frameId; 20 | 21 | /** 22 | * 占用内存的进程ID 23 | */ 24 | private int processId; 25 | 26 | public Frame(int frameId,int status){ 27 | this.frameId=frameId; 28 | this.status=status; 29 | } 30 | 31 | public int getStatus() { 32 | return status; 33 | } 34 | 35 | public void setStatus(int status) { 36 | this.status = status; 37 | } 38 | 39 | public int getFrameId() { 40 | return frameId; 41 | } 42 | 43 | public void setFrameId(int frameId) { 44 | this.frameId = frameId; 45 | } 46 | 47 | public int getProcessId() { 48 | return processId; 49 | } 50 | 51 | public void setProcessId(int processId) { 52 | this.processId = processId; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /磁盘调度算法/Java/algorithms/FCFS.java: -------------------------------------------------------------------------------- 1 | package algorithms; 2 | 3 | /** 4 | * @author Discard-001 5 | * @className FCFS 6 | * @date : 2023/05/13/ 17:35 7 | **/ 8 | public class FCFS { 9 | private int n; // 磁盘请求数目 10 | private int[] request; // 磁盘请求序列 11 | private int head; // 磁头初始位置 12 | 13 | public FCFS(int n, int[] request, int head) { 14 | this.n = n; 15 | this.request = request; 16 | this.head = head; 17 | } 18 | 19 | public int schedule() { 20 | int distance = 0; // 磁头移动距离 21 | int seekTime = 0; // 磁头寻道总距离 22 | System.out.println("FCFS算法调度过程如下:"); 23 | for (int i = 0; i < n; i++) { 24 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 25 | seekTime += distance; // 累加磁头寻道距离 26 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 27 | head = request[i]; // 更新磁头位置 28 | } 29 | System.out.println("FCFS算法调度结束"); 30 | System.out.println("总移动距离为:" + seekTime); 31 | System.out.println("平均寻道长度为:" + (double)seekTime / n); 32 | return seekTime; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /进程调度算法/golang/model/Process.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // 进程状态枚举 : https://zhuanlan.zhihu.com/p/427532561 8 | const ( 9 | BLOCK = iota 10 | READY 11 | ) 12 | 13 | type Process struct { 14 | Pid int // 进程id 15 | Status int // 进程状态 16 | Order int // 进程优先级 17 | RunTime int // 进程执行时间 18 | arriveTime *time.Time // 进程到达时间 19 | FinishTime *time.Time // 进程完成时间 20 | cycleTime int // 进程周转时间 21 | aveCycleTime int // 平均周转时间 22 | Preemption float64 // HRRN 算法的优先权 23 | } 24 | 25 | func Constructor(pid, runTime int) Process { 26 | now := time.Now() 27 | return Process{ 28 | Pid: pid, 29 | Status: 0, 30 | Order: 0, 31 | RunTime: runTime, 32 | arriveTime: &now, 33 | cycleTime: 0, 34 | aveCycleTime: 0, 35 | Preemption: 0, 36 | } 37 | } 38 | 39 | func ConstructorOrder(pid, runTime, order int) Process { 40 | now := time.Now() 41 | return Process{ 42 | Pid: pid, 43 | Status: 0, 44 | Order: order, 45 | RunTime: runTime, 46 | arriveTime: &now, 47 | cycleTime: 0, 48 | aveCycleTime: 0, 49 | Preemption: 0, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /页面置换算法/C++/sample/LFUExample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/7. 3 | // 4 | 5 | #include "../algorithms/LFU.cpp" 6 | #include 7 | #include 8 | #include 9 | 10 | time_t seed = time(nullptr); 11 | //创建一个引擎。命名为eng,并用指定种子初始化随机数序列。 12 | std::default_random_engine eng(seed); 13 | std::uniform_int_distribution dist(1, 10);//创建一个分布。 14 | std::uniform_int_distribution dist2(1, 100);//创建一个分布。 15 | 16 | void testNBlock(int n,int times){ 17 | std::cout<<"\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "<get((int)(dist(eng))); 24 | } 25 | 26 | std::cout << "\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: " 27 | << cache->getMissingNum()<<" 总次数:" << cache->getTimes() 28 | <<" 缺页率: "<<1.0*cache->getMissingNum()/times << std::endl; 29 | 30 | } 31 | 32 | int main(){ 33 | //解决控制条乱码问题 34 | system("chcp 65001"); 35 | //可以设置测试次数 36 | int num = 5; 37 | std::cout << "测试前准备测试页如下: " << std::endl; 38 | 39 | for(int i=0; i< num;i++) 40 | testNBlock(dist(eng),dist2(eng)); 41 | 42 | return 0; 43 | } -------------------------------------------------------------------------------- /页面置换算法/C++/sample/LRUExample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/6. 3 | // 4 | #include "../algorithms/LRU.cpp" 5 | #include 6 | #include 7 | #include 8 | 9 | time_t seed = time(nullptr); 10 | //创建一个引擎。命名为eng,并用指定种子初始化随机数序列。 11 | std::default_random_engine eng(seed); 12 | std::uniform_int_distribution dist(1, 10);//创建一个分布。 13 | std::uniform_int_distribution dist2(1, 100);//创建一个分布。 14 | 15 | void testNBlock(int n,int times){ 16 | std::cout<<"\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "<get((int)(dist(eng))); 23 | } 24 | 25 | std::cout << "\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: " 26 | << cache->getMissingNum()<<" 总次数:" << cache->getTimes() 27 | <<" 缺页率: "<<1.0*cache->getMissingNum()/times << std::endl; 28 | 29 | } 30 | 31 | int main(){ 32 | //解决控制条乱码问题 33 | system("chcp 65001"); 34 | //可以设置测试次数 35 | int num = 3; 36 | std::cout << "测试前准备测试页如下: " << std::endl; 37 | // 理论上LRU算法的缺页率会随着 物理块数量的增加而降低 , 如果不明显, 可以通过加大第二个参数(访问次数)尝试 38 | for(int i=0; i< num;i++) 39 | testNBlock(dist(eng),dist2(eng)); 40 | 41 | return 0; 42 | } -------------------------------------------------------------------------------- /页面置换算法/C++/sample/ClockUpdateExample.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/8. 3 | // 4 | 5 | #include "../algorithms/ClockUpdate.cpp" 6 | #include 7 | #include 8 | #include 9 | 10 | time_t seed = time(nullptr); 11 | //创建一个引擎。命名为eng,并用指定种子初始化随机数序列。 12 | std::default_random_engine eng(seed); 13 | std::uniform_int_distribution dist(1, 10);//创建一个分布。 14 | std::uniform_int_distribution dist2(1, 100);//创建一个分布。 15 | 16 | void testNBlock(int n,int times){ 17 | std::cout<<"\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "< 7 | #include 8 | 9 | 10 | time_t seed = time(nullptr); 11 | //创建一个引擎。命名为eng,并用指定种子初始化随机数序列。 12 | std::default_random_engine eng(seed); 13 | std::uniform_int_distribution dist(1, 10);//创建一个分布。 14 | std::uniform_int_distribution dist2(1, 100);//创建一个分布。 15 | 16 | void testNBlock(int n, int times) { 17 | std::cout << "\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 " << n << std::endl; 18 | 19 | // 设置lru序列的容量为n 20 | auto clockSimple = ClockSimple(n); 21 | 22 | 23 | for (int i = 1; i <= times; i++) { 24 | clockSimple.get((int) (dist(eng))); 25 | } 26 | 27 | std::cout << "\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: " 28 | << clockSimple.getMissingNum() << " 总次数:" << clockSimple.getTimes() 29 | << " 缺页率: " << 1.0 * clockSimple.getMissingNum() / clockSimple.getTimes() << std::endl; 30 | } 31 | 32 | int main() { 33 | //解决控制条乱码问题 34 | system("chcp 65001"); 35 | //可以设置测试次数 36 | int num = 5; 37 | std::cout << "测试前准备测试页如下: " << std::endl; 38 | 39 | for (int i = 0; i < num; i++) 40 | testNBlock(dist(eng), dist2(eng)); 41 | 42 | return 0; 43 | } -------------------------------------------------------------------------------- /磁盘调度算法/Python/algorithm/CSCAN.py: -------------------------------------------------------------------------------- 1 | from FCFS import * 2 | def CSCAN(track_request): 3 | global SCAN_DIRECTION 4 | queue_CSCAN = [] 5 | queue_CSCAN.append(TRACK_START) 6 | track_request_copy = copy.deepcopy(track_request) 7 | track_request_copy.sort() 8 | i = 0 9 | is_find = False 10 | 11 | if SCAN_DIRECTION == 1: 12 | while i < track_request_copy.__len__(): 13 | if (TRACK_START <= track_request_copy[i]) & (is_find == False): 14 | index = i 15 | i = 0 16 | is_find = True 17 | if is_find == True: 18 | queue_CSCAN.append(track_request_copy[index % TRACK_REQUEST_COUNT]) 19 | index += 1 20 | i += 1 21 | 22 | if SCAN_DIRECTION == 0: 23 | track_request_copy.reverse() 24 | while i < track_request_copy.__len__(): 25 | if (TRACK_START >= track_request_copy[i]) & (is_find == False): 26 | index = i 27 | i = 0 28 | is_find = True 29 | if is_find == True: 30 | queue_CSCAN.append(track_request_copy[index % TRACK_REQUEST_COUNT]) 31 | index += 1 32 | current = track_request_copy[index % TRACK_REQUEST_COUNT] 33 | i += 1 34 | 35 | return queue_CSCAN 36 | 37 | -------------------------------------------------------------------------------- /动态分区匹配算法/README.md: -------------------------------------------------------------------------------- 1 | ## 动态分区匹配算法 2 | 3 | 动态分区匹配算法是计算机内存管理中,用于动态分配内存空间的一种常见算法。 4 | 其基本思想是将可用内存空间划分为多个大小不同的分区,根据程序请求内存空间的大小,从分区中找到一个合适的空闲分区,并将其分配给程序使用。 5 | 6 | > 动态分区匹配算法存在着内存碎片的问题。当分配和释放内存的次数增多时,会产生大量的空闲分区,导致内存碎片化,使得内存空间无法充分利用。 7 | 8 | --- 9 | ### 首次适应算法(First Fit): 10 | **执行方式**:从内存的起始位置开始搜索,找到第一个大小大于等于请求的空闲分区,将其分配给程序使用。 11 | 12 | **特性**:简单易实现,适用于内存分配比较稳定的场景。但是可能会产生大量的内存碎片,影响内存利用率。 13 | 14 | **优劣**:优点是算法简单,执行效率高,缺点是易产生内存碎片,内存利用率低。 15 | 16 | --- 17 | ### 循环首次适应算法(Next Fit): 18 | **执行方式**:与首次适应算法类似,但是从上一次分配的位置开始搜索,避免了每次都从内存起始位置开始搜索的开销。 19 | 20 | **特性**:相对于首次适应算法,避免了每次都从内存起始位置开始搜索的开销,适用于内存分配比较稳定的场景。但是同样可能会产生内存碎片。 21 | 22 | **优劣**:优点是减少了搜索开销,执行效率略有提高,缺点是同样易产生内存碎片,内存利用率低。 23 | 24 | --- 25 | ### 最佳适应算法(Best Fit): 26 | **执行方式**:从所有空闲分区中找到大小最接近请求大小的分区,将其分配给程序使用。 27 | 28 | **特性**:可以最大程度地利用内存空间,减少内存碎片的产生,适用于内存分配比较频繁的场景。但是需要搜索整个空闲分区列表,效率较低。 29 | 30 | **优劣**:优点是可以最大程度地利用内存空间,减少内存碎片的产生,缺点是执行效率较低,需要搜索整个空闲分区列表。 31 | 32 | --- 33 | ### 最坏适应算法(Worst Fit): 34 | **执行方式**:从所有空闲分区中找到大小最大的分区,将其分配给程序使用。 35 | 36 | **特性**:可以减少内存碎片的产生,适用于内存分配比较频繁的场景。但是会导致大量的空闲分区存在于内存中,降低了内存利用率。 37 | 38 | **优劣**:优点是可以减少内存碎片的产生,缺点是会导致大量的空闲分区存在于内存中,降低了内存利用率。 39 | 40 | --- 41 | ### 快速适应算法(Quick Fit): 42 | **执行方式**:将内存划分为多个固定大小的分区,每个分区维护一个空闲分区链表,根据请求大小找到对应大小的分区链表,从该链表中找到一个空闲分区分配给程序使用。 43 | 44 | **特性**:可以快速地分配内存空间,适用于内存分配比较频繁且规律的场景。但是需要预留大量的空闲分区,浪费了一部分内存空间。 45 | 46 | **优劣**:优点是可以快速地分配内存空间,执行效率高,缺点是需要预留大量的空闲分区,浪费了一部分内存空间。 -------------------------------------------------------------------------------- /磁盘调度算法/C++/algorithms/LIFO.cpp: -------------------------------------------------------------------------------- 1 | // 2 | //最不常用(LIFO)调度算法 3 | // Created by dhrzbz on 2023/5/23. 4 | // 5 | // 6 | //最不常用(LIFO)调度算法:优先处理最近不常用的磁盘请求。 7 | //这种调度算法可以减少 8 | //磁盘访问时间,但可能会导致⼀些常⽤的磁盘请求⻓时间等待。 9 | // 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | bool cmp_by_value(const pair& lhs, const pair& rhs) { 18 | return lhs.second < rhs.second; //改变排序规则,以map的值为从小到大排 19 | } 20 | class LFIO 21 | { 22 | private: 23 | int Max; //磁盘请求数目 24 | vector> v; //磁盘请求序列及最近访问次数 25 | public: 26 | 27 | LFIO(map m, int n) //初始化map存入vector数组 28 | { 29 | Max = n; 30 | for (auto i : m) 31 | { 32 | v.push_back(i); 33 | } 34 | } 35 | void handle() 36 | { 37 | sort(v.begin(), v.end(), cmp_by_value);//给vector排序 38 | for (auto i : v)//按排好顺序处理请求序列 39 | { 40 | cout << i.first << endl; 41 | } 42 | cout << "处理完成" << endl; 43 | v.clear();//清空数组序列 44 | 45 | } 46 | }; 47 | int main() 48 | { 49 | cout << "请输入磁盘请求数目:"; 50 | int n; // 磁盘请求数目 51 | cin >> n; 52 | map m; // 磁盘请求序列 53 | int x, y; 54 | cout << "请输入磁盘请求序列:" << endl; 55 | for (int i = 0; i < n; i++) { 56 | cin >> x >> y; // 输入磁盘请求目标,次数 57 | m.insert(pair(x, y)); 58 | } 59 | LFIO lifo(m, n);//创建LIFO序列 60 | lifo.handle();//调用handel处理 61 | return 0; 62 | } -------------------------------------------------------------------------------- /磁盘调度算法/README.md: -------------------------------------------------------------------------------- 1 | ## 磁盘调度算法 2 | 磁盘调度算法的目的很简单,就是为了提高磁盘的访问性能,一般是通过优化磁盘的访问请求顺序来做到的。 3 | 寻道的时间是磁盘访问最耗时的部分,如果请求顺序优化的得当,必然可以节省一些不必要的寻道时间,从而提高磁盘的访问性能。 4 | ### FCFS调度(先来先服务) 5 | 磁盘调度的最简单形式当然是先来先服务(FCFS)算法。虽然这种算法比较公平,但是它通常并不提供最快的服务。 6 | 例如,考虑一个磁盘队列,其 I/O 请求块的柱面的顺序如下: 98,183,37,122,14,124,65,67。 7 | 如果磁头开始位于柱面 53,那么它首先从 53 移到 98,接着再到 183、37、122、14、124、65,最后到 67,磁头移动柱面的总数为 640。 8 | ![](http://oss.dhx.icu/dhx/1.png) 9 | 10 | ### SSTF调度(最短寻道时间优先) 11 | 在移动磁头到别处以便处理其他请求之前,处理靠近当前磁头位置的所有请求可能较为合理。这个假设是最短寻道时间优先(SSTF)算法的基础。SSTF 算法选择处理距离当前磁头位置的最短寻道时间的请求。换句话说,SSTF 选择最接近磁头位置的待处理请求。 12 | 对于上面请求队列的示例,与开始磁头位置(53)的最近请求位于柱面 65。一旦位于柱面 65,下个最近请求位于柱面 67。从那里,由于柱面 37 比 98 还要近,所以下次处理 37。如此,会处理位于柱面 14 的请求,接着 98,122,124,最后183。 13 | ![](http://oss.dhx.icu/dhx/2.png) 14 | 15 | ### SCAN调度(电梯算法) 16 | 对于扫描算法,磁臂从磁盘的一端开始,向另一端移动;在移过每个柱面时,处理请求。当到达磁盘的另一端时,磁头移动方向反转,并继续处理。磁头连续来回扫描磁盘。SCAN 算法有时称为电梯算法,因为磁头的行为就像大楼里面的电梯,先处理所有向上的请求,然后再处理相反方向的请求。 17 | 下面回到前面的例子来说明。在采用 SCAN 来调度柱面 98、183、37、122、14、124、65 和 67 的请求之前,除了磁头的当前位置,还需知道磁头的移动方向。 18 | 假设磁头朝 0 移动并且磁头初始位置还是 53,磁头接下来处理 37,然后 14。在柱面 0 时,磁头会反转,移向磁盘的另一端,并处理柱面 65、67、98、122、124、183(图 3)上的请求。如果请求刚好在磁头前方加入队列,则它几乎马上就会得到服务;如果请求刚好在磁头后方加入队列,则它必须等待,直到磁头移到磁盘的另一端,反转方向,并返回。 19 | ![](http://oss.dhx.icu/dhx/3.png) 20 | 21 | ### C-SCAN 22 | 首先自里向外访问,当磁头移到最外的磁道并访问后,磁头返回到最里的欲访问磁道,即将最小磁道号紧接着最大磁道号构成循环,继续循环扫描 直至无更外的磁道需要访问时,才将磁臂换向为自外向里移动; 23 | 下一个访问的磁道在当前位置内为距离最近者;直至再无更里面的磁道要访问。 24 | ![](http://oss.dhx.icu/dhx/5.png) -------------------------------------------------------------------------------- /进程调度算法/Python/example/MLFQExample.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 MLFQ算法测试 2 | import MLFQ 3 | 4 | if __name__ == '__main__': 5 | # 产生进程 6 | process_dict = { 7 | 'A': MLFQ.Process('A', 0, 4, 1), 8 | 'B': MLFQ.Process('B', 1, 3, 2), 9 | 'C': MLFQ.Process('C', 2, 4, 1), 10 | 'D': MLFQ.Process('D', 3, 2, 2), 11 | 'E': MLFQ.Process('E', 4, 4, 1) 12 | } 13 | 14 | # 使用RR调度算法,时间片为1 15 | print('---------------------------轮转调度算法--------------------------') 16 | rr = MLFQ.RR(process_dict, 1) 17 | rr.scheduling() 18 | 19 | # 使用多级反馈队列调度算法 20 | print() 21 | print('-----------------------测试多级反馈队列调度算法----------------------') 22 | queue_list = [MLFQ.PriorityQueue(), MLFQ.PriorityQueue(), MLFQ.PriorityQueue()] 23 | time_slices = [1, 2, 4] 24 | 25 | for process in process_dict.values(): 26 | queue_list[0].add(process.priority, process) 27 | 28 | mlfq = MLFQ.MultilevelFeedbackQueue(queue_list, time_slices) 29 | mlfq.scheduling() 30 | 31 | # 输出结果 32 | for name, process in process_dict.items(): 33 | print("Process {}:".format(name)) 34 | print("\tArrive time: {}".format(process.arrive_time)) 35 | print("\tServe time: {}".format(process.serve_time)) 36 | print("\tFinish time: {}".format(process.finish_time)) 37 | print("\tCycling time: {}".format(process.cycling_time)) 38 | print("\tWeighted cycling time: {}".format(process.w_cycling_time)) 39 | -------------------------------------------------------------------------------- /进程调度算法/Python/model.py: -------------------------------------------------------------------------------- 1 | class Process: 2 | def __init__(self, pid, priority, arr_time, all_time, cpu_time, start_block, block_time, state): ##初始化进程 3 | self.pid = pid # 进程id 4 | self.priority = priority # 进程的优先级,用于确定首先执行的进程。 5 | self.arr_time = arr_time # 到达时间,进程到达就绪队列的时间。 6 | self.all_time = all_time # 分配的时间,分配给流程的总时间量 7 | self.cpu_time = cpu_time # CPU 时间,进程已经在 CPU 上花费的时间。 8 | self.start_block = start_block # 启动块,分配给进程的启动内存块 9 | self.block_time = block_time # 阻塞时间,进程被阻止的时间。 10 | self.state = state # 进程的当前状态 11 | 12 | def Output(self): # fcfs输出 13 | print("进程" + str(self.pid), "正在执行,到达时间:" + str(self.arr_time), 14 | "还需运行时间:" + str(self.all_time), "已运行时间:" + str(self.cpu_time)) 15 | 16 | def toBlock(self): # 将状态置为Block 17 | self.state = "Block" 18 | 19 | def toRun(self): # 将状态置为Run 20 | self.state = "Run" 21 | 22 | def toFinish(self): # 将状态置为Finish 23 | self.state = "Finish" 24 | 25 | def toReady(self): # 将状态置为Ready 26 | self.state = "Ready" 27 | 28 | def running(self): ##进程运行时状态变化 29 | self.all_time -= 1 30 | self.cpu_time += 1 31 | 32 | def toBlocking(self): ##进程将要开始阻塞的状态变化 33 | if self.start_block > 0: 34 | self.start_block -= 1 35 | 36 | def blocking(self): ##进程阻塞时的状态变化 37 | if self.block_time > 0: 38 | self.block_time -= 1 39 | self.priority += 1 40 | -------------------------------------------------------------------------------- /磁盘调度算法/Java/sample/Example.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import algorithms.CSCAN; 4 | import algorithms.FCFS; 5 | import algorithms.SCAN; 6 | import algorithms.SSTF; 7 | import util.TestUtil; 8 | 9 | import java.util.Scanner; 10 | 11 | /** 12 | * @author Discard-001 13 | * @className Example 14 | * @date : 2023/05/13/ 17:55 15 | **/ 16 | public class Example { 17 | public static void main(String[] args) { 18 | compareTest(); 19 | } 20 | 21 | /** 22 | * 通用测试: 单独测试某个算法的表现情况 23 | */ 24 | static void commonTest() { 25 | int size = 20; // 磁盘序列的大小 26 | int head = 0; // 磁头的初始位置; 27 | int min = 10; // 磁道的最小值 28 | int max = 200;// 磁道的最大值 29 | // 通过通用测试类进行测试 30 | // 修改第一个方法来选定需要测试的算法 31 | TestUtil.algorithmTest(FCFS.class, size, min, max, head); 32 | TestUtil.algorithmTest(CSCAN.class, size, min, max, head); 33 | TestUtil.algorithmTest(SCAN.class, size, min, max, head); 34 | TestUtil.algorithmTest(SSTF.class, size, min, max, head); 35 | } 36 | 37 | /** 38 | * 对比测试: 测试相同数据下各个算法的表现情况 39 | */ 40 | static void compareTest() { 41 | int size = 20; // 磁盘序列的大小 42 | int head = 0; // 磁头的初始位置; 43 | int min = 10; // 磁道的最小值 44 | int max = 200;// 磁道的最大值 45 | // 对比测试 46 | Class[] classes = new Class[]{FCFS.class,CSCAN.class,SCAN.class,SSTF.class}; 47 | TestUtil.algorithmTest(classes, size, min, max, head); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /动态分区匹配算法/python/algorithms/QuickFit.py: -------------------------------------------------------------------------------- 1 | 2 | from algorithms.FirstFit import * 3 | ##最佳适应算法 4 | def bubble_sort(list): 5 | # 冒泡排序 6 | count = len(list) 7 | for i in range(0, count): 8 | for j in range(i + 1, count): 9 | if list[i].length < list[j].length: 10 | list[i], list[j] = list[j], list[i] 11 | return list 12 | def alloc2(taskID, Tasklength, li): 13 | q = copy.copy(li) 14 | q = bubble_sort(q) 15 | s = -1 16 | ss12 = -1 17 | for i in range(0, len(q)): 18 | p = q[i] 19 | if p.state == 1 and p.length > Tasklength: 20 | s = p.start 21 | elif p.state == 1 and p.length == Tasklength: 22 | ss12 = p.start 23 | if s == -1 and ss12 == -1: 24 | print("内存空间不足") 25 | return 26 | for i in range(0, len(li)): 27 | p = li[i] 28 | if p.start == s: 29 | node2 = node(p.start + Tasklength, p.end, p.length - Tasklength, 1, 0) 30 | a = node(p.start, p.start + Tasklength - 1, Tasklength, state=0, ID=taskID) 31 | print("已分配",a.Id, ' :start ', a.start, " end ", a.end, " length ", a.length) 32 | del li[i] 33 | li.insert(i, node2) 34 | li.insert(i, a) 35 | # showList(li) 36 | return 37 | elif p.start == ss12: 38 | print("已分配",taskID, ' :start ', p.start, " end ", p.end, " length ", p.length) 39 | p.state = 0 40 | showList(li) 41 | return 42 | -------------------------------------------------------------------------------- /动态分区匹配算法/python/algorithms/WorstFit.py: -------------------------------------------------------------------------------- 1 | 2 | from algorithms.FirstFit import * 3 | ##最坏适应算法 4 | def bubble_sort2(list): 5 | # 冒泡排序 6 | count = len(list) 7 | for i in range(0, count): 8 | for j in range(i + 1, count): 9 | if list[i].length > list[j].length: 10 | list[i], list[j] = list[j], list[i] 11 | return list 12 | def alloc3(taskID, Tasklength, li): 13 | q = copy.copy(li) 14 | q = bubble_sort2(q) 15 | s = -1 16 | ss12 = -1 17 | for i in range(0, len(q)): 18 | p = q[i] 19 | if p.state == 1 and p.length > Tasklength: 20 | s = p.start 21 | elif p.state == 1 and p.length == Tasklength: 22 | ss12 = p.start 23 | if s == -1 and ss12 == -1: 24 | print("内存空间不足") 25 | return 26 | for i in range(0, len(li)): 27 | p = li[i] 28 | if p.start == s: 29 | node2 = node(p.start + Tasklength, p.end, p.length - Tasklength, 1, 0) 30 | a = node(p.start, p.start + Tasklength - 1, Tasklength, state=0, ID=taskID) 31 | print("已分配",a.Id, ' :start ', a.start, " end ", a.end, " length ", a.length) 32 | del li[i] 33 | li.insert(i, node2) 34 | li.insert(i, a) 35 | # showList(li) 36 | return 37 | elif p.start == ss12: 38 | print("已分配",taskID, ' :start ', p.start, " end ", p.end, " length ", p.length) 39 | p.state = 0 40 | showList(li) 41 | return 42 | 43 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/sample/FCFSSample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.FCFS; 4 | import com.dhx.model.Process; 5 | 6 | 7 | /** 8 | * @author dhx_ 9 | * @className FCFSSample 10 | * @date : 2023/03/27/ 22:11 11 | **/ 12 | public class FCFSSample { 13 | public static final String BASE_PID="1000"; 14 | static FCFS fcfs ; 15 | 16 | 17 | public static void main(String[] args) { 18 | // 使用thread.sleep 模拟进程的执行 19 | fcfs = new FCFS(5); 20 | Thread addThread = new Thread(() -> { 21 | addProcess2Queue(6, 5, 3); 22 | }); 23 | Thread runThread = new Thread(() -> { 24 | fcfs.start(); 25 | }); 26 | addThread.start(); 27 | runThread.start(); 28 | } 29 | 30 | 31 | /** 32 | * 添加进程 33 | * 34 | * @param size 进程的数量 35 | * @param maxRunTime 生成的进程的最大执行时间 36 | * @param maxSleepTime 生成进程的过程中的最大间隔时间 37 | */ 38 | private static void addProcess2Queue(int size, int maxRunTime, int maxSleepTime) { 39 | for (int i = 0; i < size; i++) { 40 | Process process = new Process(Integer.parseInt(BASE_PID) + i + 1, (int) ((Math.random() * 10) % maxRunTime) + 1); 41 | fcfs.addProcess(process); 42 | try { 43 | Thread.sleep(1000 * (int) ((Math.random() * 10) % maxSleepTime)); 44 | } catch (InterruptedException e) { 45 | throw new RuntimeException(e); 46 | } 47 | } 48 | } 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Java/com/dhx/algorithms/lru/DoubleList.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms.lru; 2 | 3 | /** 4 | * @author dhx_ 5 | * @className DoubleList 6 | * @date : 2023/02/17/ 19:28 7 | **/ 8 | public class DoubleList { 9 | /** 10 | * 头尾虚节点 11 | */ 12 | private Node head, tail; 13 | 14 | /** 15 | * 链表元素数 16 | */ 17 | private int size; 18 | 19 | public DoubleList() { 20 | // 初始化双向链表的数据 21 | head = new Node(0, 0); 22 | tail = new Node(0, 0); 23 | head.next = tail; 24 | tail.pre = head; 25 | size = 0; 26 | } 27 | 28 | /** 29 | * 在链表尾部添加节点 x,时间 O(1) 30 | * @param x 需要添加的node 31 | */ 32 | public void addLast(Node x) { 33 | x.pre = tail.pre; 34 | x.next = tail; 35 | tail.pre.next = x; 36 | tail.pre = x; 37 | size++; 38 | } 39 | 40 | /** 41 | * 删除链表中的 x 节点(x 一定存在) , 由于是双链表且给的是目标 Node 节点,时间 O(1) 42 | * @param x 43 | */ 44 | public void remove(Node x) { 45 | x.pre.next = x.next; 46 | x.next.pre = x.pre; 47 | size--; 48 | } 49 | 50 | /** 51 | * 删除链表中第一个节点,并返回该节点,时间 O(1) 52 | * @return 53 | */ 54 | public Node removeFirst() { 55 | if (head.next == tail) 56 | return null; 57 | Node first = head.next; 58 | remove(first); 59 | return first; 60 | } 61 | 62 | /** 63 | * 返回链表长度,时间 O(1) 64 | * @return 65 | */ 66 | public int size() { return size; } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/model/DoubleLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.dhx.model; 2 | 3 | /** 4 | * @author dhx_ 5 | * @className DoubleList 6 | * @date : 2023-5-5 17:40:16 7 | **/ 8 | public class DoubleLinkedList { 9 | /** 10 | * 头尾虚节点 11 | */ 12 | private Element head, tail; 13 | 14 | /** 15 | * 链表元素数 16 | */ 17 | private int size; 18 | 19 | public DoubleLinkedList() { 20 | // 初始化双向链表的数据 21 | head = new Element(0, 0); 22 | tail = new Element(0, 0); 23 | head.next = tail; 24 | tail.pre = head; 25 | size = 0; 26 | } 27 | 28 | /** 29 | * 在链表尾部添加节点 x,时间 O(1) 30 | * @param x 需要添加的element 31 | */ 32 | public void addLast(Element x) { 33 | x.pre = tail.pre; 34 | x.next = tail; 35 | tail.pre.next = x; 36 | tail.pre = x; 37 | size++; 38 | } 39 | 40 | /** 41 | * 删除链表中的 x 节点(x 一定存在) , 由于是双链表且给的是目标 element 节点,时间 O(1) 42 | * @param x 43 | */ 44 | public void remove(Element x) { 45 | x.pre.next = x.next; 46 | x.next.pre = x.pre; 47 | size--; 48 | } 49 | 50 | /** 51 | * 删除链表中第一个节点,并返回该节点,时间 O(1) 52 | * @return 53 | */ 54 | public Element removeFirst() { 55 | if (head.next == tail) 56 | return null; 57 | Element first = head.next; 58 | remove(first); 59 | return first; 60 | } 61 | 62 | /** 63 | * 返回链表长度,时间 O(1) 64 | * @return 65 | */ 66 | public int size() { return size; } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/model/FramePartitionNode.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author adorabled4 8 | * @className FramePartitionNode Frame分区, 基于Frame类的二次封装 , 用于实现Quick Fit 算法 9 | * @date : 2023/05/16/ 13:33 10 | **/ 11 | public class FramePartitionNode { 12 | 13 | 14 | /** 15 | * 分区的大小 16 | */ 17 | private int size; 18 | 19 | 20 | /** 21 | * 当前分区的状态 22 | */ 23 | private int status; 24 | 25 | /** 26 | * 分区唯一标识 27 | */ 28 | private int id; 29 | 30 | /** 31 | * Frame数组, 实际存储 32 | */ 33 | private List mem; 34 | 35 | 36 | public FramePartitionNode(int cap,int id){ 37 | this.size=cap; 38 | mem=new ArrayList<>(cap); 39 | for (int i = 0; i < cap; i++) { 40 | Frame frame = new Frame(id + i, DMConstant.FREE); 41 | mem.add(frame); 42 | } 43 | this.id=id; 44 | this.status=DMConstant.FREE; 45 | } 46 | 47 | public int getSize() { 48 | return size; 49 | } 50 | 51 | public void setSize(int size) { 52 | this.size = size; 53 | } 54 | 55 | public int getStatus() { 56 | return status; 57 | } 58 | 59 | public void setStatus(int status) { 60 | this.status = status; 61 | } 62 | 63 | public int getId() { 64 | return id; 65 | } 66 | 67 | public void setId(int id) { 68 | this.id = id; 69 | } 70 | 71 | public List getMem() { 72 | return mem; 73 | } 74 | 75 | public void setMem(List mem) { 76 | this.mem = mem; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Golang/lru/lru.go: -------------------------------------------------------------------------------- 1 | package lru 2 | 3 | import ( 4 | "container/list" 5 | "fmt" 6 | ) 7 | 8 | type LRUCache struct { 9 | cap int 10 | cache map[int]int 11 | list *list.List // 导入包 12 | } 13 | 14 | func Constructor(capacity int) LRUCache { 15 | return LRUCache{ 16 | cap: capacity, 17 | cache: make(map[int]int), 18 | list: list.New(), 19 | } 20 | } 21 | 22 | func (this *LRUCache) Get(key int) int { 23 | if val, ok := this.cache[key]; ok { 24 | // 将 key 移动到链表尾部表示最近访问 25 | this.makeRecently(key) 26 | return val 27 | } 28 | return -1 29 | } 30 | 31 | func (this *LRUCache) Put(key int, value int) { 32 | if _, ok := this.cache[key]; ok { 33 | // 修改 key 的值,将 key 移动到链表尾部表示最近访问 34 | this.cache[key] = value 35 | this.makeRecently(key) 36 | return 37 | } 38 | 39 | if len(this.cache) >= this.cap { 40 | // 链表头部就是最久未使用的 key 41 | this.removeOldest() 42 | } 43 | // 将新的 key-value 添加链表尾部 44 | this.cache[key] = value 45 | this.list.PushBack(key) 46 | } 47 | 48 | func (this *LRUCache) makeRecently(key int) { 49 | // 将 key 移动到链表尾部表示最近访问 50 | for e := this.list.Front(); e != nil; e = e.Next() { 51 | if e.Value.(int) == key { 52 | this.list.MoveToBack(e) 53 | break 54 | } 55 | } 56 | } 57 | 58 | func (this *LRUCache) removeOldest() { 59 | // 删除链表头部表示最久未使用的 key 60 | e := this.list.Front() 61 | delete(this.cache, e.Value.(int)) 62 | this.list.Remove(e) 63 | } 64 | 65 | func (this *LRUCache) PrintList() { 66 | node := this.list.Front() 67 | fmt.Print("{") 68 | for node != nil { 69 | if node.Next() != nil { 70 | fmt.Print(node.Value, "->") 71 | } else { 72 | fmt.Print(node.Value) 73 | break 74 | } 75 | node = node.Next() 76 | } 77 | fmt.Print("}\n") 78 | } 79 | -------------------------------------------------------------------------------- /磁盘调度算法/Java/algorithms/CSCAN.java: -------------------------------------------------------------------------------- 1 | package algorithms; 2 | 3 | 4 | import java.util.Arrays; 5 | 6 | /** 7 | * @author Discard-001 8 | * @className CSCAN 9 | * @date : 2023/05/13/ 17:36 10 | **/ 11 | public class CSCAN { 12 | private int n; // 磁盘请求数目 13 | private int[] request; // 磁盘请求序列 14 | private int head; // 磁头初始位置 15 | 16 | public CSCAN(int n, int[] request, int head) { 17 | this.n = n; 18 | this.request = request; 19 | this.head = head; 20 | Arrays.sort(request); // 对请求序列进行升序排序 21 | } 22 | 23 | public int schedule() { 24 | int distance = 0; // 磁头移动距离 25 | int seekTime = 0; // 磁头寻道时间 26 | System.out.println("C-SCAN算法调度过程如下:"); 27 | int first = -1; 28 | for (int i = 0; i < n; i++) { 29 | if (head <= request[i + 1]) { 30 | first = i; 31 | break; 32 | } 33 | } 34 | for (int i = first + 1; i < n; i++) { 35 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 36 | seekTime += distance; // 累加磁头寻道距离 37 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 38 | head = request[i]; // 更新磁头位置 39 | } 40 | for (int i = 0; i <= first; i++) { 41 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 42 | seekTime += distance; // 累加磁头寻道距离 43 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 44 | head = request[i]; // 更新磁头位置 45 | } 46 | System.out.println("CSCAN算法调度结束"); 47 | System.out.println("总移动距离为:" + seekTime); 48 | System.out.println("平均寻道长度为:" + (double)seekTime / n); 49 | return seekTime; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /动态分区匹配算法/python/algorithms/BestFit.py: -------------------------------------------------------------------------------- 1 | 2 | from python.algorithms.FirstFit import * 3 | # 循环首次适应算法 4 | def alloc1(taskID, Tasklength, list): 5 | global p_sign, p_num, time 6 | if time == 0: 7 | p_sign = list[0] 8 | time = 1 9 | for i in range(0, len(list)): 10 | p = list[i] 11 | if (p.start - 1) == p_sign.end: 12 | p_num = i 13 | for i in range(p_num, len(list)): 14 | p = list[i] 15 | if p.state == 1 and p.length > Tasklength: 16 | node2 = node(p.start + Tasklength, p.end, p.length - Tasklength, 1, 0) 17 | a = node(p.start, p.start + Tasklength - 1, Tasklength, state=0, ID=taskID) 18 | print("已分配",a.Id, ' :start ', a.start, " end ", a.end, " length ", a.length) 19 | p_sign = a 20 | del list[i] 21 | list.insert(i, node2) 22 | list.insert(i, a) 23 | # showList(list) 24 | return 25 | if p.state == 1 and p.length == Tasklength: 26 | print("已分配",taskID, ' :start ', p.start, " end ", p.end, " length ", p.length) 27 | p.state = 0 28 | showList(list) 29 | return 30 | for i in range(p_num): 31 | p = list[i] 32 | if p.state == 1 and p.length > Tasklength: 33 | node2 = node(p.start + Tasklength, p.end, p.length - Tasklength, 1, 0) 34 | a = node(p.start, p.start + Tasklength - 1, Tasklength, state=0, ID=taskID) 35 | p_sign = a 36 | del list[i] 37 | list.insert(i, node2) 38 | list.insert(i, a) 39 | showList(list) 40 | return 41 | if p.state == 1 and p.length == Tasklength: 42 | p.state = 0 43 | showList(list) 44 | return 45 | print("内存空间不足") 46 | -------------------------------------------------------------------------------- /进程调度算法/C++/model/PCB.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/7. 3 | // 4 | 5 | #ifndef IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_PCB_H 6 | #define IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_PCB_H 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | // 就绪态 15 | #define W "waitting" 16 | // 运行态 17 | #define R "running" 18 | // 完成态w 19 | #define F "finished" 20 | //最多100个进程 21 | const int N = 100; 22 | //通用属性 23 | struct PCB { 24 | int id; //进程编号 25 | string Name;//进程名字 26 | double arriveTime;//进程到达时间 27 | double serviceTime;//进程需要服务时间 28 | double rserviceTime;//进程剩余服务时间 29 | double endTime;//已服务时间 30 | double finishTime;//完成时间点记录 31 | double RunTime;//进程周转时间 32 | double avgTime; //带权周转时 33 | string State;//进程状态 34 | int st; // 开始时间 35 | int weight;//进程的优先级(权重) 36 | }; 37 | 38 | //声明一个RR类 39 | class RR{ 40 | public: 41 | queueRRqueue; //用来模拟进程执行RR调度算法的队列 42 | double SumWT=0,SumWWT=0,AverageWT =0,AverageWWT=0;//平均周转时间、平均带权周转时间 43 | int q; //时间片数 44 | int n; //进程个数 45 | PCB RRarray[N]; //进程结构体 46 | 47 | }; 48 | static RR RRobject; 49 | 50 | //声明一个SLF类 51 | class SLF{ 52 | public: 53 | double SumWT=0,SumWWT=0,AverageWT =0,AverageWWT=0;//平均周转时间、平均带权周转时间 54 | int q; //时间片数 55 | int n; //进程个数 56 | PCB SLFarray[N]; //进程结构体 57 | 58 | }; 59 | static SLF SLFobject; 60 | 61 | //声明一个PS类 62 | class PS{ 63 | public: 64 | PCB PSarray[N]; 65 | int n; 66 | double CurrentTime;//声明当前时间 67 | vector WaitList; 68 | }; 69 | static PS PSobject; 70 | 71 | //声明一个SRTF类 72 | class SRTF{ 73 | public: 74 | int n;//进程数 75 | vector SRTFarray; 76 | }; 77 | static SRTF SRTFobject; 78 | #endif //IMPLEMENTATION_OF_OS_CLASSICAL_ALGORITHM_PCB_H 79 | -------------------------------------------------------------------------------- /磁盘调度算法/C++/algorithms/FCFS.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 先来先服务(FCFS)调度算法 3 | // Created by 侯金科 on 2023/5/12. 4 | // 5 | /* 6 | * FCFS算法是先来先服务算法,它根据进程请求访问磁盘的先后顺序进行调度, 7 | * 不考虑磁头的移动方向和距离。它的优点是公平、简单,每个进程请求都能依次得到处理, 8 | * 不会出现饥饿现象。它的缺点是平均寻道时间较长,适用于磁盘I/O进程数目较少的场合。 9 | */ 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | class FCFS { 15 | private: 16 | int n; // 磁盘请求数目 17 | int* request; // 磁盘请求序列 18 | int head; // 磁头初始位置 19 | public: 20 | FCFS(int n, int* request, int head) { 21 | this->n = n; 22 | this->request = request; 23 | this->head = head; 24 | } 25 | 26 | void schedule() { 27 | int distance = 0; // 磁头移动距离 28 | int seekTime = 0; // 磁头寻道总距离 29 | cout << "FCFS算法调度过程如下:" << endl; 30 | for (int i = 0; i < n; i++) { 31 | distance = abs(request[i] - head); // 计算磁头移动距离 32 | seekTime += distance; // 累加磁头寻道距离 33 | cout << "从" << head << "号磁道移动到" << request[i] << "号磁道,移动距离为" << distance << endl; 34 | head = request[i]; // 更新磁头位置 35 | } 36 | cout << "FCFS算法调度结束" << endl; 37 | cout << "总移动距离为:" << seekTime << endl; 38 | cout << "平均寻道长度为:" << (double)seekTime / n << endl; 39 | } 40 | }; 41 | 42 | int main() { 43 | //解决CLion控制台乱码问题 44 | system("chcp 65001"); 45 | cout << "请输入磁盘请求数目:" << endl; 46 | int n; // 磁盘请求数目 47 | cin >> n; 48 | int* request = new int[n]; // 磁盘请求序列 49 | cout << "请输入磁盘请求序列:" << endl; 50 | for (int i = 0; i < n; i++) { 51 | cin >> request[i]; // 输入磁盘请求序列 52 | } 53 | cout << "请输入磁头初始位置:" << endl; 54 | int head; // 磁头初始位置 55 | cin >> head; 56 | 57 | FCFS fcfs(n, request, head); // 创建FCFS对象 58 | fcfs.schedule(); // 调用schedule方法进行调度 59 | 60 | delete[] request; // 释放动态数组内存 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /进程调度算法/README.md: -------------------------------------------------------------------------------- 1 | ## 进程调度算法 2 | ### FCFS(first-come first-served) 3 | FCFS是最简单的调度算法,该算法既可用于**作业调度**,也可用于**进程调度**。 4 | 当在作业调度中采用该算法时,系统将按照作业到达的先后次序来进行调度,或者说它是优先考虑在系统中等待时间最长的作业,而不管该作业所需执行的时间的长短,从后备作业队列中选择几个最先进入该队列的作业,将它们调入内存,为它们分配资源和创建进程。 5 | 然后把它放入就绪队列。 6 | 7 | FCFS调度算法属于不可剥夺算法。 8 | 从表面上看,它对所有作业都是公平的,但若一个长作业先到达系统,就会使后面的许多短作业等待很长时间,因此它不能作为分时系统和实时系统的主要调度策略。 9 | 但它常被结合在其他调度策略中使用。例如,在使用优先级作为调度策略的系统中,往往对多个具有相同优先级的进程按FCFS原则处理。 10 | 11 | FCFS调度算法的特点是算法简单,但效率低;对长作业比较有利,但对短作业不利(相对SJF和高响应比);有利于CPU繁忙型作业,而不利于IO繁忙型作业。 12 | 13 | ### SJF/ SPF Shortest Job/Process First 14 | 短作业(进程)优先调度算法是指对短作业(进程)优先调度的算法。 15 | 短作业优先(SJF)调度算法从后备队列中选择一个或若干估计运行时间最短的作业,将它们调入内存运行; 16 | 短进程优先(SPF)调度算法从就绪队列中选择一个估计运行时间最短的进程,将处理机分配给它,使之立即执行,直到完成或发生某事件而阻塞时,才释放处理机。 17 | > SJF 调度算法的平均等待时间、平均周转时间最少。 18 | 19 | ### 优先级调度算法 20 | 优先级调度算法又称优先权调度算法,它既可用于作业调度,又可用于进程调度。该算法中的优先级**用于描述作业运行的紧迫程度**。 21 | 优先级调度算法每次从就绪队列中选择优先级最高的进程,将处理机分配给它,使之投入运行。 22 | 23 | 24 | ### HRRN 高响应比优先(Highest Response Ratio Next) 25 | 26 | 高响应比优先调度算法主要用于作业调度,是对FCFS调度算法和SJF调度算法的一种综合平衡, 27 | 同时考虑了每个作业的等待时间和估计的运行时间。在每次进行作业调度时,先计算后备作业队列中每个作业的响应比,从中选出响应比最高的作业投入运行 28 | 29 | *优先权=(等待时间 + 要求服务时间)/要求服务时间* 30 | 31 | ### 多级反馈队列调度算法(Multi-Level Feedback Queue) 32 | 33 | 多级反馈队列调度算法是一种常用的进程调度算法,基于时间片轮转算法和多级反馈队列算法。 34 | 35 | 它使用多个队列来管理进程,并为每个队列分配不同大小的时间片。 36 | 37 | 进程首先被放入第一级队列,如果在运行期间消耗完了它的时间片,那么它就会被移到下一级队列中,直到所有的队列都运行完毕。 38 | 39 | 该算法的主要特点是,允许进程在不同级别的队列之间移动,并**使具有高优先级的进程尽快得到处理**,**从而避免低优先级进程永远得不到处理的情况**。 40 | 41 | 当一个进程进入队列时,它被赋予一个初始优先级,根据进程的行为和系统的需求,优先级可以上升或下降。例如,如果一个进程在第一级队列运行了一段时间,在使用完指定时间片后仍然没有完成它的任务,那么它将被重新插入到第二级队列中。 42 | 43 | > 多级反馈队列轮转算法是一种高效的进程调度算法,可以使具有高优先级的进程尽快得到处理,同时避免低优先级进程永远得不到处理的情况。它的实现需要维护多个队列和时间片大小,以及每个进程已经运行的时间和优先级等信息。 44 | 45 | --- 46 | ### 参考 47 | - https://blog.csdn.net/qq_43511405/article/details/109089439 48 | - https://zhuanlan.zhihu.com/p/585138200 49 | - https://blog.csdn.net/weixin_46013401/article/details/110819774 -------------------------------------------------------------------------------- /进程调度算法/Python/SJF.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 SJF算法 2 | global N 3 | N = 5 4 | pcb = [] 5 | 6 | 7 | # 输入函数 8 | def inPcb(): 9 | global N 10 | i = 0 11 | while i < N: 12 | print("****************************************") 13 | pName = input("请输入进程名 :") # 进程名 14 | inTime = input("请输入进入时间:") # 进入时间 15 | serverTime = input("请输入服务时间:") # 服务时间 16 | # 数据按顺序存放到列表中 startTime=开始时间 finishTime=完成时间 zzTime=周转时间 dqzzTime=带权周转时间 17 | # 进程名 进入时间 服务时间 开始 完成 周转 带权 18 | pcb.append([pName, inTime, serverTime, 0, 0, 0, 0]) 19 | i = i + 1 20 | 21 | 22 | # 短作业优先 23 | def sjf(): 24 | sjf_pcb = pcb 25 | temp_pcb = pcb[1:len(sjf_pcb)] # 切片 临时存放后备队列 len(sjf_pcb)获取长度。 26 | temp_pcb.sort(key=lambda x: x[2], reverse=False) # 对后背队列 按照服务时间排序 27 | sjf_pcb[1:len(sjf_pcb)] = temp_pcb 28 | i = 0 29 | for i in range(N): 30 | if i == 0: 31 | startTime = int(sjf_pcb[0][1]) 32 | pcb[0][3] = startTime 33 | pcb[0][4] = startTime + int(sjf_pcb[0][2]) 34 | else: 35 | startTime = sjf_pcb[i - 1][4] 36 | pcb[i][3] = startTime 37 | pcb[i][4] = startTime + int(sjf_pcb[i][2]) 38 | i = i + 1 39 | for i in range(N): 40 | sjf_pcb[i][5] = int(sjf_pcb[i][4]) - int(sjf_pcb[i][1]) # 周转时间 41 | sjf_pcb[i][6] = float(sjf_pcb[i][5]) / int(sjf_pcb[i][2]) # 带权周转时间 42 | i = i + 1 43 | # 输出结果 44 | pcb.sort(key=lambda x: x[0], reverse=False) # 升序排序 按照进程名排序 45 | print('短作业优先SJF运行结果:') 46 | for i in range(N): 47 | print("进程名:%s 进入时间:%d 服务时间:%d 开始时间:" 48 | "%d 完成时间:%d 周转时间:%d 带权周转时间:%.2f" 49 | % (sjf_pcb[i][0], int(sjf_pcb[i][1]), int(sjf_pcb[i][2]), int(sjf_pcb[i][3]), 50 | int(sjf_pcb[i][4]), float(sjf_pcb[i][5]), float(sjf_pcb[i][6]))) 51 | 52 | -------------------------------------------------------------------------------- /磁盘调度算法/Java/algorithms/SSTF.java: -------------------------------------------------------------------------------- 1 | package algorithms; 2 | 3 | /** 4 | * @author Discard-001 5 | * @className SSTF 6 | * @date : 2023/05/13/ 17:35 7 | **/ 8 | public class SSTF { 9 | private int n; // 磁盘请求数目 10 | private int[] request; // 磁盘请求序列 11 | private int head; // 磁头初始位置 12 | private boolean[] visited; // 标记请求是否已被处理 13 | 14 | public SSTF(int n, int[] request, int head) { 15 | this.n = n; 16 | this.request = request; 17 | this.head = head; 18 | this.visited = new boolean[n]; // 创建动态布尔数组 19 | for (int i = 0; i < n; i++) { 20 | visited[i] = false; // 初始化为未访问 21 | } 22 | } 23 | 24 | public int schedule() { 25 | int distance = 0; // 磁头移动距离 26 | int seekTime = 0; // 磁头寻道总距离 27 | System.out.println("SSTF算法调度过程如下:"); 28 | for (int i = 0; i < n; i++) { 29 | int minDistance = Integer.MAX_VALUE; // 最小寻道距离,初始为最大整数 30 | int minIndex = -1; // 最小寻道距离对应的请求序号,初始为-1 31 | for (int j = 0; j < n; j++) { 32 | if (!visited[j]) { // 如果请求未被处理 33 | distance = Math.abs(request[j] - head); // 计算磁头移动距离 34 | if (distance < minDistance) { // 如果距离小于当前最小距离 35 | minDistance = distance; // 更新最小距离 36 | minIndex = j; // 更新最小距离对应的序号 37 | } 38 | } 39 | } 40 | seekTime += minDistance; // 累加磁头寻道距离 41 | System.out.println("从" + head + "号磁道移动到" + request[minIndex] + "号磁道,移动距离为" + minDistance); 42 | head = request[minIndex]; // 更新磁头位置 43 | visited[minIndex] = true; // 标记请求已被处理 44 | } 45 | System.out.println("SSTF算法调度结束"); 46 | System.out.println("总移动距离为:" + seekTime); 47 | System.out.println("平均寻道长度为:" + (double)seekTime / n); 48 | return seekTime; 49 | } 50 | } -------------------------------------------------------------------------------- /进程调度算法/Python/RR.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.05.19 RR算法 2 | 3 | import random 4 | 5 | 6 | def createP(p_num): # 创建字典,根据输入的进程数进行创建进程字典,时间为随机1-9s之间 7 | p_dict = {} 8 | # 获取一个a-z的列表 9 | alphabet_list = list(map(chr, range(ord('a'), ord('z') + 1))) 10 | 11 | for i in range(0, p_num): 12 | # 默认进程名为a-z顺序排序 13 | p_dict[alphabet_list[i]] = random.randint(1, 9) 14 | return p_dict 15 | 16 | 17 | def lunzhuanP(p_dict, p_num): # 开始轮转 18 | print("进程名称" + " " * 10 + "每个进程需要工作的时间") 19 | p_time = {} 20 | p_list = [[-1 for i in range(4)] for j in range(p_num + 1)] 21 | # 添加输出头 22 | p_list[0][0] = "Name" 23 | p_list[0][1] = "run" 24 | p_list[0][2] = "req" 25 | p_list[0][3] = "status" 26 | z = 1 27 | for k, v in p_dict.items(): 28 | # 将进程初始化设置初始值 29 | p_list[z][0] = k 30 | p_list[z][1] = 0 31 | p_list[z][2] = v 32 | p_list[z][3] = "R" 33 | p_time[k] = 0 34 | z += 1 35 | 36 | for k, v in p_dict.items(): 37 | print(k + " ", v) 38 | j = 1 39 | t = 1 40 | while True: 41 | if len(p_list) == 1: 42 | print("进程执行完毕") 43 | for k, v in p_time.items(): 44 | print("进程%s的执行周期为:%s" % (k, v)) 45 | break 46 | 47 | # 判断是否有进程执行完毕 48 | for y in range(1, len(p_list) - 1): 49 | 50 | if p_list[y][3] == "E": 51 | del p_list[y] 52 | 53 | if j <= len(p_list) - 1: 54 | 55 | if p_list[j][1] + 1 <= p_list[j][2]: 56 | 57 | p_list[j][1] += 1 58 | 59 | if p_list[j][1] == p_list[j][2]: 60 | p_list[j][3] = "E" 61 | else: 62 | 63 | del p_list[j] 64 | continue 65 | 66 | else: 67 | j = j - len(p_list) + 1 68 | continue 69 | 70 | print("cpu时刻: ", t) 71 | print("正在执行的进程:", p_list[j][0]) 72 | p_time[p_list[j][0]] += 1 73 | j += 1 74 | t += 1 75 | for i in range(len(p_list)): 76 | print(p_list[i]) 77 | -------------------------------------------------------------------------------- /页面置换算法/C++/algorithms/ClockUpdate.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/8. 3 | // 4 | #include "../model/Mem.h" 5 | 6 | const int N = 20; 7 | 8 | class ClockUpdate { 9 | int capacity;//页容量 10 | int idx;//内存指针 11 | int times;//调度总次数 12 | int MissingNum;//缺页次数 13 | Mem mem[N]; 14 | public: 15 | ClockUpdate(int capacity) { 16 | this->capacity = capacity; 17 | idx = 0; 18 | times = 0; 19 | MissingNum = 0; 20 | } 21 | 22 | void get(int x) { 23 | int tmp = -1; 24 | times++; 25 | for (int i = 0; i < capacity; i++) { 26 | if (mem[i].pageNum == x) tmp = i; 27 | } 28 | if (tmp) { 29 | idx = tmp; 30 | mem[idx].visit = 1; 31 | } else { 32 | //如果内存没有 33 | MissingNum++; //缺页次数++ 34 | for (int i = idx; i < idx+capacity; i++){ 35 | //遇到访问位为1,置0 36 | if (mem[idx].visit == 1) { 37 | mem[idx].visit = 0; 38 | } else if(mem[idx].modify==0){ 39 | mem[idx].pageNum = x; 40 | mem[idx].visit = 1; 41 | mem[idx].modify = 1; 42 | break; 43 | } 44 | //指针循环遍历 45 | idx++; 46 | if (idx == capacity) idx = 0; 47 | } 48 | if(mem[idx].pageNum!=x){ 49 | while(true){ 50 | //遇到访问位为1,置0 51 | if (mem[idx].modify == 1){ 52 | mem[idx].pageNum = x; 53 | mem[idx].visit = 1; 54 | mem[idx].modify = 1; 55 | break; 56 | } 57 | //指针循环遍历 58 | idx++; 59 | if (idx == capacity) idx = 0; 60 | } 61 | } 62 | } 63 | //return tmp;//返回现存内存块,-1表示不在 64 | } 65 | 66 | int getTimes() const { 67 | return times; 68 | } 69 | 70 | int getMissingNum() const { 71 | return MissingNum; 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /页面置换算法/C++/algorithms/ClockSimple.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/8. 3 | // 4 | #include "../model/Mem.h" 5 | #include 6 | const int N = 20; 7 | 8 | class ClockSimple { 9 | int capacity;//页容量 10 | int idx;//内存指针 11 | int times;//调度总次数 12 | int MissingNum;//缺页次数 13 | Mem mem[N]; 14 | public: 15 | ClockSimple(int capacity) { 16 | this->capacity = capacity; 17 | idx = 0; 18 | times = 0; 19 | MissingNum = 0; 20 | } 21 | 22 | int get(int x) { 23 | int tmp = -1; 24 | times++; 25 | for (int i = 0; i < capacity; i++) { 26 | if (mem[i].pageNum == x) tmp = i; 27 | } 28 | if (tmp) { 29 | idx = tmp; 30 | mem[idx].visit = 1; 31 | } else { 32 | //如果内存没有 33 | MissingNum++; //缺页次数++ 34 | while (true) { 35 | //遇到访问位为1,置0 36 | if (mem[idx].visit == 1) { 37 | mem[idx].visit = 0; 38 | } else { //访问位为0,置换页面 39 | mem[idx].pageNum = x; 40 | mem[idx].visit = 1; 41 | break; 42 | } 43 | //指针循环遍历 44 | idx++; 45 | if (idx == capacity) idx = 0; 46 | } 47 | } 48 | return tmp;//返回现存内存块,-1表示不在 49 | } 50 | 51 | int getTimes() const { 52 | return times; 53 | } 54 | 55 | int getMissingNum() const { 56 | return MissingNum; 57 | } 58 | }; 59 | 60 | //int main(){ 61 | // system("chcp 65001"); 62 | // 63 | // auto clockSimple = ClockSimple(4); 64 | // 65 | // std::cout<= this.cap { 30 | process.Status = model.BLOCK 31 | this.block = append(this.block, process) 32 | } else { 33 | this.Ready = append(this.Ready, process) 34 | } 35 | } 36 | 37 | func (this *FCFS) Start() { 38 | for { 39 | // 每次间歇 40 | time.Sleep(time.Duration(100) * time.Millisecond) 41 | if len(this.Ready)+len(this.block) > 0 { 42 | this.execute() 43 | } 44 | } 45 | } 46 | 47 | func (this *FCFS) execute() { 48 | for this.running != nil || len(this.Ready)+len(this.block) > 0 { 49 | if len(this.Ready) < 1 { 50 | this.fromBlock2Ready() 51 | } 52 | // 判断当前进程是否存在 53 | if this.running == nil { 54 | this.running = &this.Ready[0] 55 | this.Ready = this.Ready[1:] 56 | time.Sleep(time.Second * time.Duration(this.running.RunTime)) 57 | fmt.Println(getNowTime()+"\033[32m[finish]\033[0m执行完毕 , 进程ID :", this.running.Pid, " 耗时: ", this.running.RunTime, "(s)") 58 | } else { 59 | time.Sleep(time.Second * time.Duration(this.running.RunTime)) 60 | fmt.Println(getNowTime()+"\033[32m[finish]\033[0m执行完毕 , 进程ID :", this.running.Pid, " 耗时: ", this.running.RunTime, "(s)") 61 | } 62 | this.running = nil 63 | } 64 | } 65 | 66 | // 把程序从阻塞队列移动到等待队列 67 | func (this *FCFS) fromBlock2Ready() { 68 | for len(this.Ready) < this.cap && len(this.block) > 0 { 69 | process := this.block[len(this.block)-1] 70 | process.Status = model.READY 71 | this.Ready = append(this.Ready, process) 72 | this.block = this.block[:len(this.block)-1] // 利用切片 73 | } 74 | } 75 | 76 | func getNowTime() string { 77 | return time.Now().Format("2006-01-02 15:04:05") + " " 78 | } 79 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/sample/NRUExample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.nru.NRU; 4 | import com.dhx.model.Element; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static com.dhx.model.Constant.elements; 10 | 11 | /** 12 | * @author dhx_ 13 | * @className NRUSample 14 | * @date : 2023-5-9 12:58:00 15 | **/ 16 | public class NRUExample { 17 | 18 | public static void main(String[] args) { 19 | System.out.println("测试前准备测试页如下: "); 20 | for (Element element : elements) { 21 | System.out.println(element); 22 | } 23 | // 理论上NRU算法的缺页率会随着 物理块数量的增加而降低 , 如果不明显, 可以通过加大第二个参数(访问次数)尝试 24 | List results = new ArrayList<>(); 25 | results.add(testNBlock(3, 1000)); 26 | results.add(testNBlock(4, 1000)); 27 | results.add(testNBlock(6, 1000)); 28 | results.add(testNBlock(8, 1000)); 29 | results.add(testNBlock(10, 100)); 30 | results.forEach(System.out::println); 31 | /* 32 | 实际测试结果 33 | [测试结束]物理块数: 3 缺页次数: 666 缺页率: 0.666 34 | [测试结束]物理块数: 4 缺页次数: 605 缺页率: 0.605 35 | [测试结束]物理块数: 6 缺页次数: 415 缺页率: 0.415 36 | [测试结束]物理块数: 8 缺页次数: 222 缺页率: 0.222 37 | [测试结束]物理块数: 10 缺页次数: 0 缺页率: 0.0 38 | */ 39 | } 40 | 41 | /** 42 | * 随机调用十次页数 43 | * @param n 设置物理块数量为n 44 | * @param times 测试次数 45 | */ 46 | static String testNBlock(int n,int times){ 47 | System.out.println("\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "+n); 48 | if(n>10){ 49 | throw new RuntimeException("测试块数过多!"); 50 | } 51 | // 设置NRU序列的容量为n 52 | NRU cache = new NRU(n); 53 | // 假设我们最开始直接放入3个页面到内存块中, 54 | for (int i = 1; i <= n; i++) { 55 | cache.put(elements[i]); 56 | } 57 | for (int i = 1; i <= times; i++) { 58 | int random = (int)(Math.random()*100)%10+1; 59 | cache.get(random); 60 | } 61 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: "+cache.getMissingNum() + "缺页率: "+cache.getMissingNum()/(double)times + " 当前页面情况: " + cache.toString() ); 62 | return "\u001B[31m\u001B[1m[测试结束]\u001B[0m物理块数: "+n+" 缺页次数: "+cache.getMissingNum() + " 缺页率: "+cache.getMissingNum()/(double)times; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/sample/LRUExample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.lfu.LFU; 4 | import com.dhx.model.Element; 5 | import com.dhx.algorithms.lru.LRU; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static com.dhx.model.Constant.elements; 11 | 12 | /** 13 | * @author dhx_ 14 | * @className LruSample 15 | * @date : 2023/02/17/ 12:41 16 | **/ 17 | public class LRUExample { 18 | 19 | public static void main(String[] args) { 20 | System.out.println("测试前准备测试页如下: "); 21 | for (Element element : elements) { 22 | System.out.println(element); 23 | } 24 | // 理论上LRU算法的缺页率会随着 物理块数量的增加而降低 , 如果不明显, 可以通过加大第二个参数(访问次数)尝试 25 | List results = new ArrayList<>(); 26 | results.add(testNBlock(3, 1000)); 27 | results.add(testNBlock(4, 1000)); 28 | results.add(testNBlock(6, 1000)); 29 | results.add(testNBlock(8, 1000)); 30 | results.add(testNBlock(10, 1000)); 31 | results.forEach(System.out::println); 32 | /* 33 | 实际测试结果 34 | [测试结束]物理块数: 3 缺页次数: 720 缺页率: 0.72 35 | [测试结束]物理块数: 4 缺页次数: 627 缺页率: 0.627 36 | [测试结束]物理块数: 6 缺页次数: 393 缺页率: 0.393 37 | [测试结束]物理块数: 8 缺页次数: 219 缺页率: 0.219 38 | [测试结束]物理块数: 10 缺页次数: 0 缺页率: 0.0 39 | */ 40 | } 41 | 42 | /** 43 | * 随机调用十次页数 44 | * @param n 设置物理块数量为n 45 | * @param times 测试次数 46 | */ 47 | static String testNBlock(int n,int times){ 48 | System.out.println("\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "+n); 49 | if(n>10){ 50 | throw new RuntimeException("测试块数过多!"); 51 | } 52 | // 设置lru序列的容量为n 53 | LRU cache = new LRU(n); 54 | // 假设我们最开始直接放入3个页面到内存块中, 55 | for (int i = 1; i <= n; i++) { 56 | cache.put(elements[i]); 57 | } 58 | for (int i = 1; i <= times; i++) { 59 | int random = (int)(Math.random()*100)%10+1; 60 | cache.get(random); 61 | } 62 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: "+cache.getMissingNum() + "缺页率: "+cache.getMissingNum()/(double)times + " 当前页面情况: " + cache.toString() ); 63 | return "\u001B[31m\u001B[1m[测试结束]\u001B[0m物理块数: "+n+" 缺页次数: "+cache.getMissingNum() + " 缺页率: "+cache.getMissingNum()/(double)times; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/sample/SJFSample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.FCFS; 4 | import com.dhx.algorithms.SJF; 5 | import com.dhx.model.Process; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * @author dhx_ 13 | * @className FCFSSample 14 | * @date : 2023/03/27/ 22:11 15 | **/ 16 | public class SJFSample { 17 | public static final String BASE_PID="1000"; 18 | public static int cnt=0; 19 | static SJF sjf; 20 | 21 | public static void main(String[] args) { 22 | sjf = new SJF(5); 23 | new Thread(()->{ 24 | addProcess2Queue(6,5,5); 25 | }).start(); 26 | sjf.start(); 27 | } 28 | 29 | /** 30 | * 添加进程 31 | * @param size 进程的数量 32 | * @param maxRunTime 生成的进程的最大执行时间 33 | * @param maxSleepTime 生成进程的过程中的最大间隔时间 34 | */ 35 | private static void addProcess2Queue(int size,int maxRunTime ,int maxSleepTime){ 36 | for (int i = 0; i < size; i++) { 37 | Process process = new Process(Integer.parseInt(BASE_PID) + i, (int) ((Math.random()*10)%maxRunTime)+1); 38 | sjf.addProcess(process); 39 | try { 40 | Thread.sleep(1000 * (int) ((Math.random()*10)%maxSleepTime)); 41 | } catch (InterruptedException e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | } 46 | 47 | 48 | /** 49 | * 旧的示例 , 可以直接写死进程的执行时间以及到达时间等 , **随机的实现可能体现不出来算法的特性** 50 | */ 51 | private static void oldSample(){ 52 | // 使用thread.sleep 模拟进程的执行 53 | // 可以看到 虽然 B C进程都在等待队列里面, 并且B是先到达的进程, 但是由于B的执行时间长于C,因此先执行C进程 54 | new Thread(()->{ 55 | Process processA= new Process(Integer.parseInt(BASE_PID)+cnt++,3); 56 | Process processB= new Process(Integer.parseInt(BASE_PID)+cnt++,2); 57 | Process processC= new Process(Integer.parseInt(BASE_PID)+cnt++,1); 58 | try { 59 | sjf.addProcess(processA); 60 | Thread.sleep(1000); // 设置间隔时间 61 | sjf.addProcess(processB); 62 | Thread.sleep(1000); 63 | sjf.addProcess(processC); 64 | } catch (InterruptedException e) { 65 | throw new RuntimeException(e); 66 | } 67 | }).start(); 68 | sjf.start(); 69 | } 70 | 71 | } 72 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Implementation of os classical algorithm 2 | 3 | os经典算法实现 4 | 5 | ## 项目结构说明 6 | 7 | 下面以测试目录的页面置换算法为例 , 说明本项目的结构 8 | 9 | ``` 10 | └─页面置换算法(测试) 11 | ├─golang 12 | │ ├─.idea 13 | │ └─lru 14 | ├─Java 15 | │ └─com 16 | │ └─dhx 17 | │ ├─algorithms 18 | │ │ └─lru 19 | │ └─sample 20 | └─Python 21 | └─mx 22 | ├─algorithm 23 | └─sample 24 | ``` 25 | 26 | 第一级目录为某方面算法的名称 , 比如置换算法、调度算法等。 27 | 28 | 第二级目录为某方面算法的**具体语言实现** ,例如页面置换算法(测试) 29 | 30 | ``` 31 | 32 | └─页面置换算法(测试) 33 | ├─golang 34 | ├─Java 35 | └─Python 36 | ``` 37 | 38 | 第三级目录一般就是对应编程语言的实现代码,其中**algorithms**目录存放的为算法实现, 39 | **sample**目录(或者是文件)存放的为操作示例 40 | 41 | ## 贡献 42 | 43 | > 如果您在浏览本仓库的过程中发现了什么问题,欢迎您提出issue,我们欢迎所有人来为我们的项目做出贡献。 44 | > - 指出问题并不一定是代码方面,可以是任何方面的问题,即使是文档中有一个错别字或者是格式有什么问题, 45 | > 如果您能够帮助我们**指出问题**或者是提出pull request,我们也会热烈的欢迎! 46 | > - 如果您想要向本项目进行pull request,请您务必预先浏览**贡献流程** 47 | 48 | ### 代码规范 49 | 50 | #### Java 51 | 52 | 1. **命名**: 标识符的命名力求做到统一、达意和简洁,Java请使用驼峰法命名 53 | 2. **格式**: 请确保您的代码每个缩进为4个空格,源文件使用**utf-8**编码,行宽不要超过120。 54 | 3. **注释**: 请确保您的类、域和方法上面有相应的 Java Doc , 单行注释使用`//` 多行时用`/* ..*/`,较短的代码块用空行表示注释作用域,较长的代码块要用`/*------ start: ------*/`和`/*-------- end: -------*/`包围,可以考虑使用大括号来表示注释范围。 55 | 56 | > Java编程规范(第三版)百度云下载(.pdf):https://pan.baidu.com/s/1Di5VN-FfFPate-_fBNiXqA 57 | 58 | ### 贡献流程 59 | 60 | 理想的**贡献工作流程**概述如下: 61 | 62 | 1. fork当前代码仓库 63 | 2. 克隆项目仓库到本地 64 | 3. 更新本地分支代码,需要确认本地分支的代码是新的 65 | 4. 开始您的代码,请确保您的代码满足基本的代码规范,如变量名、排版以及必要的注释等 66 | 5. commit 和 push,请确保您的commit message 满足规范,详见https://www.conventionalcommits.org/zh-hans/v1.0.0/ 67 | 6. pull reqeust,在pull request之前请将您的分支仓库与远程仓库同步,以确保您的 PR 优雅、简洁 68 | 69 | ## 注意事项 70 | 71 | ### 运行golang代码 72 | 73 | 如果您需要直接运行golang代码,请将工作目录切换为golang文件夹,以确保代码可以正确被编译器识别 74 | 75 | ``` 76 | └─页面置换算法(测试) 77 | ├─golang 78 | ``` 79 | 80 | ![示意图](http://oss.dhx.icu/dhx/image-20230329122912749.png) 81 | 82 | ### 运行C++代码 83 | 84 | 如果您需要运行C++代码,请将工作目录切换为C++文件夹,以确保代码可以正确被编译器识别 85 | 86 | 如果使用的是CLion,请保持版本在`2023.1`以上或最新,低版本可能无法支持单文件编译 87 | 88 | 若无法使用最新版CLion,则在`2020.3`之后同样可以通过安装 C/C++ Single File Execution插件 89 | 然后在需要运行的代码中右键,点击Add executable for single c/cpp file。 90 | 这样,CLion会在CMakeLists.txt文件中添加相应的代码,并在右上角显示运行按钮。 91 | 建议使用最新版,较为方便无需配置CMake,只需要点击`main()`左侧的绿色运行按钮即可运行 92 | ![](http://oss.dhx.icu/dhx/img.png) 93 | 94 | 如果使用的是VS code,可以通过安装相关插件来运行,或者通过terminal使用`gcc/g++`运行相关文件 95 | -------------------------------------------------------------------------------- /动态分区匹配算法/Cpp/FF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | //⾸次适应算法(First-Fit) 3 | // Created by dhrzbz on 2023/5/23. 4 | // 5 | 6 | //⾸次适应算法(First - Fit): 7 | //该算法会按照地址顺序查找第⼀个能够满⾜需求的空闲 8 | //分区,并将进程放⼊其中。 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | class FF 17 | { 18 | private: 19 | map m; //存储所剩的空间大小 key:起始地址 value:大小 20 | int Max; 21 | 22 | public: 23 | FF(pair p) 24 | { 25 | m[p.first] = p.second; //初始化空间大小 26 | Max = p.second; //记录空间最大值,防止超出 27 | } 28 | void FF_add(int n) 29 | { 30 | for (auto i = m.begin(); i != m.end(); i++)//遍历寻找第一个可以放下的位置 31 | { 32 | if (i->second == n) //若大小等于目的文件大小则将该空间完全释放掉 33 | { 34 | m.erase(i); 35 | cout << "放入成功" << endl; 36 | return; 37 | } 38 | else if (i->second > n) //若大小不等于目的文件大小则将剩余空间记录 39 | { 40 | 41 | int k = i->first + n; 42 | int j = i->second - n; 43 | m.erase(i); 44 | m[k] = j; 45 | cout << "放入成功" << endl; 46 | return; 47 | } 48 | } 49 | cout << "放入失败" << endl; //空间不够 50 | } 51 | void Free(int f, int length) 52 | { 53 | if (f + length > Max) //超出空间,释放失败 54 | { 55 | cout << "释放位置空间超出范围" << endl; 56 | return; 57 | } 58 | m[f] = length; //将新释放空间存入map 59 | map ::iterator j = m.begin(); //遍历开是否可以合并空闲空间 60 | j++; 61 | for (auto i = m.begin(); j != m.end(); ) 62 | { 63 | int f_1 = i->first, f_2 = i->second, n_1 = j->first, n_2 = j->second; 64 | if (i->first + i->second == j->first) //可以合并 65 | { 66 | j++; 67 | m.erase(n_1); 68 | m[f_1] = f_2 + n_2; 69 | } 70 | else 71 | { 72 | i++; 73 | j++; 74 | } 75 | } 76 | } 77 | }; 78 | int main() 79 | { 80 | int m, n; 81 | cout << "请输入初始空间大小:"; 82 | cin >> n; 83 | FF ff(pair(0, n)); 84 | for (int i = 0; i < 5; i++) 85 | { 86 | cout << "请选择占有空间(1)或者释放空间(2):" << endl; 87 | cin >> m; 88 | if (m == 1) 89 | { 90 | cout << "请输入文件大小:"; 91 | cin >> n; 92 | cout << endl; 93 | ff.FF_add(n); 94 | } 95 | else if (m == 2) 96 | { 97 | cout << "请输入释放空间的起始地址及大小" << endl; 98 | int x, y; 99 | cin >> x >> y; 100 | cout << endl; 101 | ff.Free(x, y); 102 | 103 | } 104 | else 105 | cout << "输入错误请重新输入!" << endl; 106 | } 107 | 108 | } -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/sample/LFUExample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.fifo.FIFO; 4 | import com.dhx.algorithms.lfu.LFU; 5 | import com.dhx.model.Element; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static com.dhx.model.Constant.elements; 11 | 12 | /** 13 | * @author dhx_ 14 | * @className LFUSample 15 | * @date : 2023-5-9 10:48:43 16 | **/ 17 | public class LFUExample { 18 | 19 | public static void main(String[] args) { 20 | System.out.println("测试前准备测试页如下: "); 21 | for (Element element : elements) { 22 | System.out.println(element); 23 | } 24 | // 理论上LFU算法的缺页率会随着 物理块数量的增加而降低 , 如果不明显, 可以通过加大第二个参数(访问次数)尝试 25 | List results = new ArrayList<>(); 26 | results.add(testNBlock(3, 1000)); 27 | results.add(testNBlock(4, 1000)); 28 | results.add(testNBlock(6, 1000)); 29 | results.add(testNBlock(8, 1000)); 30 | results.add(testNBlock(10, 1000)); 31 | results.forEach(System.out::println); 32 | /* 33 | 实际测试情况 34 | 测试时建议测试加大测试数据的容量,使得结果更加趋于一般效果 35 | [测试结束]物理块数: 3 缺页次数: 706 缺页率: 0.706 36 | [测试结束]物理块数: 4 缺页次数: 578 缺页率: 0.578 37 | [测试结束]物理块数: 6 缺页次数: 402 缺页率: 0.402 38 | [测试结束]物理块数: 8 缺页次数: 198 缺页率: 0.198 39 | [测试结束]物理块数: 10 缺页次数: 0 缺页率: 0.0 40 | */ 41 | } 42 | 43 | /** 44 | * 随机调用十次页数 45 | * @param n 设置物理块数量为n 46 | * @param times 测试次数 47 | */ 48 | static String testNBlock(int n,int times){ 49 | System.out.println("\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "+n); 50 | if(n>10){ 51 | throw new RuntimeException("测试块数过多!"); 52 | } 53 | // 设置LFU序列的容量为n 54 | LFU cache = new LFU(n); 55 | // 假设我们最开始直接放入3个页面到内存块中, 56 | for (int i = 1; i <= n; i++) { 57 | cache.put(elements[i]); 58 | } 59 | for (int i = 1; i <= times; i++) { 60 | int random = (int)(Math.random()*100)%10+1; 61 | cache.get(random); 62 | } 63 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: "+cache.getMissingNum() + "缺页率: "+cache.getMissingNum()/(double)times + " 当前页面情况: " + cache.toString() ); 64 | return "\u001B[31m\u001B[1m[测试结束]\u001B[0m物理块数: "+n+" 缺页次数: "+cache.getMissingNum() + " 缺页率: "+cache.getMissingNum()/(double)times; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /页面置换算法/README.md: -------------------------------------------------------------------------------- 1 | ## 页面置换算法 2 | 页面的换入换出, 需要启动磁盘的IO 会有较大的开销 , 因此好的页面置换算法应该**追求更少的缺页率** 3 | 4 | 5 | ### 最佳置换算法 6 | - **无法实现** 7 | 8 | 最佳置换算法(OPT,Optimal): 每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。 9 | 10 | 最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。 11 | 12 | 操作系统无法提前预判页面访问序列。因此,**最佳置换算法是无法实现的**。 13 | 14 | **只有当 内存块全部占满并且出现了缺页中断 才会发生 页面置换** 15 | 16 | 17 | ### 先进先出置换算法-FIFO 18 | 先进先出置换算法(FIFO): 每次选择淘汰的页面是最早进入内存的页面 19 | 20 | 实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。队列的最大长度取决于系统为进程分配了多少个内存块。 21 | 22 | 需要注意的是,FIFO在执行的过程中可能会出现**Belady**异常 23 | 24 | Belady异常:当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。 25 | 26 | > 只有FIFO算法会产生Belady异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差。 27 | 28 | ### 最近最久未使用算法-LRU 29 | **最近最久未使用置换算法(LRU,least recently used)**: 每次淘汰的页面是最近最久未使用的页面。 30 | 31 | 实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。 32 | 33 | 当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。 34 | 35 | 36 | ### 最不经常使用算法-LFU 37 | 38 | 39 | **最不经常使用算法(Least Frequently Used, LFU)** 是一种基于页面使用频率的算法,用于管理虚拟内存中的页面置换 。 40 | LFU算法会记录每个页面被访问的次数,然后在物理内存不足时,选择访问次数最少的页面进行置换。 41 | 42 | 该算法置换最少被使用的页面。为了实现该算法,操作系统需要记录每个页面被使用的次数。 43 | 当物理内存不足时,将页表中使用次数最小的页面移出物理内存,然后将新页面移入物理内存。 44 | 45 | **LFU算法需要记录每个页面的访问次数,因此可能会增加额外的开销,但在某些情况下可能比LRU算法更好。** 46 | 47 | ### 时钟置换算法-NRU 48 | > 最佳置换算法性能最好,但无法实现;先进先出置换算法实现简单,但算法性能差;最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,算法开销大。 49 | 50 | 时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或**最近未用算法(NRU,NotRecently Used)** 51 | 52 | 简单的CLOCK 算法实现方法: 53 | 54 | 为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。 55 | 56 | 当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。 57 | 58 | 如果是0,就选择该页换出; 59 | 60 | 如果是1,则将它置为0,暂不换出,继续检查下一个页面, 61 | 62 | 若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描) 63 | 64 | 65 | ### 改进型的时钟置换算法 66 | 简单的时钟置换算法仅考虑到一个页面最近是否被访问过。 67 | 68 | 事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。 69 | 因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。 70 | 71 | 在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/O操作。这就是改进型的时钟置换算法的思想。修改位=0,表示页面没有被修改过;修改位=1,表示页面被修改过。 为方便讨论,用 **(访问位,修改位)** 的形式表示各页面状态。 72 | 73 | 如(1,1)表示一个页面近期被访问过,且被修改过。 74 | 算法规则: 将所有可能被置换的页面排成一个循环队列 第一轮:从当前位置开始扫描到第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位 第二轮:若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。本轮将所有扫描过的帧访问位设为0 第三轮:若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位 第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。 由于第二轮已将所有帧的访问位设为0,因此经过第三轮、第四轮扫描一定会有一个帧被选中,因此改进型CLOCK置换算法选择一个淘汰页面最多会进行四轮扫描 75 | 76 | 1. 第一优先级:最近没访问,且没修改的页面 77 | 2. 第二优先级:最近没访问,但修改过的页面 78 | 3. 第三优先级:最近访问过,但没修改的页面 79 | 4. 第四优先级:最近访问过,且修改过的页面 -------------------------------------------------------------------------------- /页面置换算法/C++/algorithms/LFU.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/6. 3 | // 4 | 5 | #include 6 | 7 | #include "../model/CacheNode.h" 8 | 9 | class LFU{ 10 | int capacity;//页容量 11 | CacheNode *head, *tail;//头尾指针 12 | std::map mp; 13 | int times;//次数 14 | int MissingNum;//缺页次数 15 | public: 16 | explicit LFU(int capacity){ 17 | this->capacity = capacity; 18 | head = nullptr; 19 | tail = nullptr; 20 | times = 0; 21 | MissingNum = 0; 22 | } 23 | 24 | //调出key页面,若没有则创建 25 | int get(int key){ 26 | auto it = mp.find(key);//map::iterator it = mp.find(key); 27 | times ++; 28 | if(it != mp.end()){ 29 | CacheNode *node = it -> second; 30 | node->value++;//调整节点的访问次数 31 | return node -> value; 32 | }else{ 33 | MissingNum++; 34 | set(key, 1); 35 | return -1; 36 | } 37 | } 38 | 39 | //调入key页面 40 | void set(int key, int value){ 41 | auto *newNode = new CacheNode(key, value); 42 | if(mp.size() >= capacity){ 43 | setHead(newNode); 44 | remove1(newNode); 45 | }else 46 | setHead(newNode); 47 | mp[key] = newNode; 48 | 49 | } 50 | 51 | //从尾部遍历,避免先调入的调出 52 | void remove1(CacheNode *node){ 53 | CacheNode * min = tail, *p = tail; 54 | 55 | while(p->pre != node){ 56 | p = p -> pre; 57 | if(min->value > p->value) 58 | min = p; 59 | } 60 | 61 | remove(min); 62 | mp.erase(mp.find(min->key)); 63 | } 64 | 65 | 66 | void remove(CacheNode *node){ 67 | if(node -> pre != nullptr) 68 | node -> pre -> next = node -> next; 69 | else head = node -> next; 70 | if(node -> next != nullptr) 71 | node -> next -> pre = node -> pre; 72 | else 73 | tail = node -> pre; 74 | } 75 | 76 | void setHead(CacheNode *node){ 77 | node -> next = head; 78 | node -> pre = nullptr; 79 | if(head != nullptr) 80 | head -> pre = node; 81 | head = node; 82 | if(tail == nullptr){ 83 | tail = head; 84 | } 85 | } 86 | 87 | int getTimes() const { 88 | return times; 89 | } 90 | 91 | int getMissingNum() const { 92 | return MissingNum; 93 | } 94 | }; 95 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/sample/FIFOExample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.fifo.FIFO; 4 | import com.dhx.algorithms.lru.LRU; 5 | import com.dhx.model.Element; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static com.dhx.model.Constant.elements; 11 | 12 | /** 13 | * @author dhx_ 14 | * @className FIFOSample 15 | * @date : 2023-5-5 15:13:42 16 | **/ 17 | public class FIFOExample { 18 | 19 | public static void main(String[] args) { 20 | System.out.println("测试前准备测试页如下: "); 21 | for (Element element : elements) { 22 | System.out.println(element); 23 | } 24 | List results = new ArrayList<>(); 25 | results.add(testNBlock(3, 1000)); 26 | results.add(testNBlock(4, 1000)); 27 | results.add(testNBlock(6, 1000)); 28 | results.add(testNBlock(8, 1000)); 29 | results.add(testNBlock(10, 1000)); 30 | results.forEach(System.out::println); 31 | /* 32 | FIFO 算法由于不会对常使用的页面进行特殊处理,添加页面之后可能破坏原本的页面顺序,因此有可能发生Belady异常(这里的页面的数量较小,因此并不明显) 33 | 实际情况是由于计算机的局部性原理,类似于LRU的算法的效果会更好 34 | 测试时建议测试加大测试数据的容量,使得结果更加趋于一般效果 35 | [测试结束]物理块数: 3 缺页次数: 701 缺页率: 0.701 36 | [测试结束]物理块数: 4 缺页次数: 605 缺页率: 0.605 37 | [测试结束]物理块数: 6 缺页次数: 431 缺页率: 0.431 38 | [测试结束]物理块数: 8 缺页次数: 216 缺页率: 0.216 39 | [测试结束]物理块数: 10 缺页次数: 0 缺页率: 0.0 40 | */ 41 | } 42 | 43 | /** 44 | * 随机调用十次页数 45 | * @param n 设置物理块数量为n 46 | * @param times 测试次数 47 | */ 48 | static String testNBlock(int n,int times){ 49 | System.out.println("\u001B[31m\u001B[1m[测试开始]\u001B[0m 本次测试物理块数量为 "+n); 50 | if(n>10){ 51 | throw new RuntimeException("测试块数过多!"); 52 | } 53 | // 设置lru序列的容量为n 54 | FIFO cache = new FIFO(n); 55 | // 假设我们最开始直接放入3个页面到内存块中, 56 | for (int i = 1; i <= n; i++) { 57 | cache.put(elements[i]); 58 | } 59 | for (int i = 1; i <= times; i++) { 60 | int random = (int)(Math.random()*100)%10+1; 61 | cache.get(random); 62 | } 63 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 缺页次数: "+cache.getMissingNum() + "缺页率: "+cache.getMissingNum()/(double)times + " 当前页面情况: " + cache.toString() ); 64 | return "\u001B[31m\u001B[1m[测试结束]\u001B[0m物理块数: "+n+" 缺页次数: "+cache.getMissingNum() + " 缺页率: "+cache.getMissingNum()/(double)times; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /页面置换算法/C++/algorithms/FIFO.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 12494 on 2023/5/14. 3 | // 4 | #include "../model/Mem.h" 5 | const int N = 100; 6 | int pages[N];// 模拟访问的页面序列 7 | int n=0;//访问次数 8 | // 计算缺页次数和缺页率 9 | int pageFaults = 0; 10 | double pageFaultRate = 0.0; 11 | // 定义一个队列,用来存储当前内存中的页面 12 | queue memory; 13 | static Mem Memobject; 14 | // 假设内存中有 3 个页面的空间 15 | void init(){ 16 | cout<<"请输入内存中的页面空间大小"; 17 | cin>>Memobject.pageNum; 18 | //模拟访问的页面序列 19 | cout<<"请输入访问的页面数"; 20 | cin>>n; 21 | cout<<"请依次输入访问的页面序列"; 22 | for(int i=0;i>pages[i]; 24 | } 25 | } 26 | // 定义一个函数,判断给定的页面是否在内存中 27 | bool isInMemory(int page) { 28 | // 遍历队列中的元素,如果找到与页面相同的元素,返回 true 29 | queue temp = memory; // 复制一份队列,避免修改原队列 30 | while (!temp.empty()) { 31 | if (temp.front() == page) { 32 | return true; 33 | } 34 | temp.pop(); 35 | } 36 | // 如果遍历完队列没有找到相同的元素,返回 false 37 | return false; 38 | } 39 | // 定义一个函数,打印当前内存中的页面 40 | void printMemory() { 41 | // 遍历队列中的元素,打印出来 42 | queue temp = memory; // 复制一份队列,避免修改原队列 43 | cout << "Memory: "; 44 | while (!temp.empty()) { 45 | cout << temp.front() << " "; 46 | temp.pop(); 47 | } 48 | cout << endl; 49 | } 50 | 51 | // 计算并输出缺页率 52 | void print(){ 53 | cout<<"缺页数为:"<{ 19 | addProcess2Queue(7,5,5,10); 20 | }).start(); 21 | priority.start(); 22 | } 23 | /** 24 | * 下面是一段测试的结果 , 可以看到进程的执行顺序通过优先级由高到低执行 25 | * 04-09 01:53:48.048[ARRIVE]进程到达, 进程ID :1000 预计用时: 2(s) 26 | * 04-09 01:53:48.048[RUNNING]执行进程 进程ID :1000 耗时: 2(s) , 进程优先级为: 9 27 | * 04-09 01:53:52.052[ARRIVE]进程到达, 进程ID :1001 预计用时: 5(s) 28 | * 04-09 01:53:52.052[RUNNING]执行进程 进程ID :1001 耗时: 5(s) , 进程优先级为: 5 29 | * 04-09 01:53:54.054[ARRIVE]进程到达, 进程ID :1002 预计用时: 3(s) 30 | * 04-09 01:53:54.054[ARRIVE]进程到达, 进程ID :1003 预计用时: 3(s) 31 | * 04-09 01:53:55.055[ARRIVE]进程到达, 进程ID :1004 预计用时: 2(s) 32 | * 04-09 01:53:57.057[RUNNING]执行进程 进程ID :1003 耗时: 3(s) , 进程优先级为: 8 33 | * 04-09 01:53:58.058[ARRIVE]进程到达, 进程ID :1005 预计用时: 2(s) 34 | * 04-09 01:54:00.000[ARRIVE]进程到达, 进程ID :1006 预计用时: 3(s) 35 | * 04-09 01:54:00.000[RUNNING]执行进程 进程ID :1006 耗时: 3(s) , 进程优先级为: 10 36 | * 04-09 01:54:03.003[RUNNING]执行进程 进程ID :1005 耗时: 2(s) , 进程优先级为: 6 37 | * 04-09 01:54:05.005[RUNNING]执行进程 进程ID :1004 耗时: 2(s) , 进程优先级为: 4 38 | * 04-09 01:54:07.007[RUNNING]执行进程 进程ID :1002 耗时: 3(s) , 进程优先级为: 1 39 | */ 40 | 41 | /** 42 | * 添加进程 43 | * @param size 进程的数量 44 | * @param maxRunTime 生成的进程的最大执行时间 45 | * @param maxSleepTime 生成进程的过程中的最大间隔时间 46 | */ 47 | private static void addProcess2Queue(int size,int maxRunTime ,int maxSleepTime,int maxOrder){ 48 | for (int i = 0; i < size; i++) { 49 | Process process = new Process(Integer.parseInt(BASE_PID) + i, (int) ((Math.random()*10)%maxRunTime)+1); 50 | // 设置进程的优先级为随机数 51 | process.setOrder((int) ((Math.random()*10)%maxOrder)+1); 52 | priority.addProcess(process); 53 | try { 54 | Thread.sleep(1000 * (int) ((Math.random()*10)%maxSleepTime)); 55 | } catch (InterruptedException e) { 56 | throw new RuntimeException(e); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /磁盘调度算法/C++/algorithms/C-SCAN.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 循环扫描(C-SCAN)调度算法 3 | // Created by 侯金科 on 2023/5/12. 4 | // 5 | 6 | /* 7 | *C-SCAN算法是循环扫描算法,它是SCAN算法的改进, 8 | * 它在磁头移动到磁盘一端并反转方向时,不处理相反方向的请求,而是直接跳到磁盘另一端的最外侧磁道, 9 | * 然后再按同一方向处理请求。它的优点是避免了磁头反转方向时的寻道时间,使请求的响应时间更加均匀。 10 | * 它的缺点是可能导致磁盘两端的请求等待时间较长。 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | using namespace std; 18 | 19 | class C_SCAN { 20 | private: 21 | int n; // 磁盘请求数目 22 | int* request; // 磁盘请求序列 23 | int head; // 磁头初始位置 24 | public: 25 | C_SCAN(int n, int* request, int head) { 26 | this->n = n; 27 | this->request = request; 28 | this->head = head; 29 | sort(request, request + n); // 对请求序列进行升序排序 30 | } 31 | 32 | void schedule() { 33 | int distance = 0; // 磁头移动距离 34 | int seekTime = 0; // 磁头寻道时间 35 | cout << "C-SCAN算法调度过程如下:" << endl; 36 | int first = -1; 37 | for(int i=0;i> n; 67 | int* request = new int[n]; // 磁盘请求序列 68 | cout << "请输入磁盘请求序列:" << endl; 69 | for (int i = 0; i < n; i++) { 70 | cin >> request[i]; // 输入磁盘请求序列 71 | } 72 | cout << "请输入磁头初始位置:" << endl; 73 | int head; // 磁头初始位置 74 | cin >> head; 75 | 76 | C_SCAN cScan(n, request, head); // 创建SCAN对象 77 | cScan.schedule(); // 调用schedule方法进行调度 78 | 79 | delete[] request; // 释放动态数组内存 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /动态分区匹配算法/python/sample/Sample.py: -------------------------------------------------------------------------------- 1 | 2 | from python.algorithms.FirstFit import * 3 | from python.algorithms.BestFit import * 4 | from python.algorithms.QuickFit import * 5 | from python.algorithms.WorstFit import * 6 | if __name__ == "__main__": 7 | while True: 8 | try: 9 | x = int(input("请选择:0首次适应算法,1循环首次适应算法,2最佳适应算法,3最坏适应算法,4退出程序")) 10 | a = node(0, 639, 640, state=1, ID=0) 11 | b = [] 12 | b.append(a) 13 | if x == 0: 14 | alloc0(1, 130, b) 15 | alloc0(2, 60, b) 16 | alloc0(3, 100, b) 17 | showList2(b) 18 | free_k(2, b) 19 | alloc0(4, 200, b) 20 | showList2(b) 21 | free_k(3, b) 22 | free_k(1, b) 23 | showList2(b) 24 | alloc0(5, 140, b) 25 | alloc0(6, 60, b) 26 | alloc0(7, 50, b) 27 | free_k(6, b) 28 | showList2(b) 29 | elif x == 1: 30 | alloc1(1, 130, b) 31 | alloc1(2, 60, b) 32 | alloc1(3, 100, b) 33 | free_k(2, b) 34 | alloc1(4, 200, b) 35 | free_k(3, b) 36 | free_k(1, b) 37 | alloc1(5, 140, b) 38 | alloc1(6, 60, b) 39 | alloc1(7, 50, b) 40 | free_k(6, b) 41 | showList2(b) 42 | elif x == 2: 43 | alloc2(1, 130, b) 44 | alloc2(2, 60, b) 45 | alloc2(3, 100, b) 46 | free_k(2, b) 47 | alloc2(4, 200, b) 48 | free_k(3, b) 49 | free_k(1, b) 50 | alloc2(5, 140, b) 51 | alloc2(6, 60, b) 52 | alloc2(7, 50, b) 53 | free_k(6, b) 54 | showList2(b) 55 | elif x == 3: 56 | alloc3(1, 130, b) 57 | alloc3(2, 60, b) 58 | alloc3(3, 100, b) 59 | free_k(2, b) 60 | alloc3(4, 200, b) 61 | free_k(3, b) 62 | free_k(1, b) 63 | alloc3(5, 140, b) 64 | alloc3(6, 60, b) 65 | alloc3(7, 50, b) 66 | free_k(6, b) 67 | showList2(b) 68 | elif x == 4: 69 | break 70 | else: 71 | print("请输入正确的选项") 72 | continue 73 | except: 74 | print("请输入正确的选项") 75 | -------------------------------------------------------------------------------- /磁盘调度算法/C++/algorithms/SSTF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 最短寻道时间优先(SSTF)调度算法 3 | // Created by 侯金科 on 2023/5/12. 4 | // 5 | /* 6 | * SSTF算法选择调度处理的磁道是与当前磁头所在磁道距离最近的磁道, 7 | * 以使每次的寻找时间最短。当然,总是选择最小寻找时间并不能保证平均寻找时间最小, 8 | * 但是能提供比FCFS算法更好的性能。这种算法会产生“饥饿”现象。 9 | */ 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | class SSTF { 16 | private: 17 | int n; // 磁盘请求数目 18 | int* request; // 磁盘请求序列 19 | int head; // 磁头初始位置 20 | bool* visited; // 标记请求是否已被处理 21 | public: 22 | SSTF(int n, int* request, int head) { 23 | this->n = n; 24 | this->request = request; 25 | this->head = head; 26 | this->visited = new bool[n]; // 创建动态布尔数组 27 | for (int i = 0; i < n; i++) { 28 | visited[i] = false; // 初始化为未访问 29 | } 30 | } 31 | 32 | ~SSTF() { 33 | delete[] visited; // 析构函数中释放动态数组内存 34 | } 35 | 36 | void schedule() { 37 | int distance = 0; // 磁头移动距离 38 | int seekTime = 0; // 磁头寻道总距离 39 | cout << "SSTF算法调度过程如下:" << endl; 40 | for (int i = 0; i < n; i++) { 41 | int minDistance = INT_MAX; // 最小寻道距离,初始为最大整数 42 | int minIndex = -1; // 最小寻道距离对应的请求序号,初始为-1 43 | for (int j = 0; j < n; j++) { 44 | if (!visited[j]) { // 如果请求未被处理 45 | distance = abs(request[j] - head); // 计算磁头移动距离 46 | if (distance < minDistance) { // 如果距离小于当前最小距离 47 | minDistance = distance; // 更新最小距离 48 | minIndex = j; // 更新最小距离对应的序号 49 | } 50 | } 51 | } 52 | seekTime += minDistance; // 累加磁头寻道距离 53 | cout << "从" << head << "号磁道移动到" << request[minIndex] << "号磁道,移动距离为" << minDistance << endl; 54 | head = request[minIndex]; // 更新磁头位置 55 | visited[minIndex] = true; // 标记请求已被处理 56 | } 57 | cout << "SSTF算法调度结束" << endl; 58 | cout << "总移动距离为:" << seekTime << endl; 59 | cout << "平均寻道长度为:" << (double)seekTime / n << endl; 60 | } 61 | }; 62 | 63 | int main() { 64 | //解决CLion控制台乱码问题 65 | system("chcp 65001"); 66 | cout << "请输入磁盘请求数目:" << endl; 67 | int n; // 磁盘请求数目 68 | cin >> n; 69 | int* request = new int[n]; // 磁盘请求序列 70 | cout << "请输入磁盘请求序列:" << endl; 71 | for (int i = 0; i < n; i++) { 72 | cin >> request[i]; // 输入磁盘请求序列 73 | } 74 | cout << "请输入磁头初始位置:" << endl; 75 | int head; // 磁头初始位置 76 | cin >> head; 77 | 78 | SSTF sstf(n, request, head); // 创建SSTF对象 79 | sstf.schedule(); // 调用schedule方法进行调度 80 | 81 | delete[] request; // 释放动态数组内存 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /动态分区匹配算法/python/algorithms/FirstFit.py: -------------------------------------------------------------------------------- 1 | 2 | import copy 3 | 4 | p_sign = None 5 | p_num = 0 6 | time = 0 7 | 8 | class node(object): 9 | def __init__(self, start, end, length, state=1, ID=0): 10 | self.start = start 11 | self.end = end 12 | self.length = length 13 | self.state = state ##state为1:内存未分配 14 | self.Id = ID ##ID为0是未分配,其余为任务编号 15 | 16 | def showList(list): 17 | """展示空闲分区""" 18 | print("空闲分区如下") 19 | id = 1 20 | for i in range(0, len(list)): 21 | p = list[i] 22 | if p.state == 1: 23 | print(id, ' :start ', p.start, " end ", p.end, " length ", p.length) 24 | id += 1 25 | 26 | def showList2(list): 27 | """展示已分配分区""" 28 | print("已分配分区如下") 29 | for i in range(0, len(list)): 30 | p = list[i] 31 | if p.state == 0: 32 | print(p.Id, ' :start ', p.start, " end ", p.end, " length ", p.length) 33 | 34 | def free_k(taskID, li): 35 | for i in range(0, len(li)): 36 | p = li[i] 37 | if p.Id == taskID: 38 | p.state = 1 39 | x = i 40 | print("已释放", taskID, ' :start ', p.start, " end ", p.end, " length ", p.length) 41 | break 42 | 43 | # 向前合并空闲块 44 | if x - 1 > 0: 45 | if li[x - 1].state == 1: 46 | a = node(li[x - 1].start, li[x].end, li[x - 1].length + li[x].length, 1, 0) 47 | del li[x - 1] 48 | del li[x - 1] 49 | li.insert(x - 1, a) 50 | x = x - 1 51 | # 向后合并空闲块 52 | if x + 1 < len(li): 53 | if li[x + 1].state == 1: 54 | a = node(li[x].start, li[x + 1].end, li[x].length + li[x + 1].length, 1, 0) 55 | del li[x] 56 | del li[x] 57 | li.insert(x, a) 58 | showList(li) 59 | 60 | # 首次适应算法 61 | def alloc0(taskID, Tasklength, list): 62 | for i in range(0, len(list)): 63 | p = list[i] 64 | if p.state == 1 and p.length > Tasklength: 65 | node2 = node(p.start + Tasklength, p.end, p.length - Tasklength, 1, 0) 66 | a = node(p.start, p.start + Tasklength - 1, Tasklength, state=0, ID=taskID) 67 | print("已分配",a.Id, ' :start ', a.start, " end ", a.end, " length ", a.length) 68 | del list[i] 69 | list.insert(i, node2) 70 | list.insert(i, a) 71 | # showList(list) 72 | return 73 | if p.state == 1 and p.length == Tasklength: 74 | print("已分配",taskID, ' :start ', p.start, " end ", p.end, " length ", p.length) 75 | p.state = 0 76 | showList(list) 77 | return 78 | print("内存空间不足") 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/sample/MLFQSample.java: -------------------------------------------------------------------------------- 1 | package com.dhx.sample; 2 | 3 | import com.dhx.algorithms.FCFS; 4 | import com.dhx.algorithms.MLFQ; 5 | import com.dhx.algorithms.SJF; 6 | import com.dhx.model.Process; 7 | 8 | 9 | /** 10 | * @author dhx_ 11 | * @className FCFSSample 12 | * @date : 2023-5-21 10:58:50 13 | **/ 14 | public class MLFQSample { 15 | public static final String BASE_PID = "1000"; 16 | public static MLFQ mlfq; 17 | 18 | public static void main(String[] args) throws InterruptedException { 19 | int[]quantum = new int[]{2, 2, 2, 4, 5}; 20 | int queueSize = 5; 21 | mlfq = new MLFQ(queueSize,quantum); 22 | Thread addThread = new Thread(() -> { 23 | addProcess2Queue(6, 10, 3); 24 | }); 25 | addThread.start(); 26 | mlfq.start(); 27 | } 28 | 29 | /** 30 | * 添加进程 31 | * 32 | * @param size 进程的数量 33 | * @param maxRunTime 生成的进程的最大执行时间 34 | * @param maxSleepTime 生成进程的过程中的最大间隔时间 35 | */ 36 | private static void addProcess2Queue(int size, int maxRunTime, int maxSleepTime) { 37 | for (int i = 0; i < size; i++) { 38 | Process process = new Process(Integer.parseInt(BASE_PID) + i + 1, (int) ((Math.random() * 10) % maxRunTime) + 1); 39 | mlfq.addProcess(process); 40 | try { 41 | Thread.sleep(1000 * (int) ((Math.random() * 10) % maxSleepTime)); 42 | } catch (InterruptedException e) { 43 | throw new RuntimeException(e); 44 | } 45 | } 46 | } 47 | 48 | /* 49 | 下面是一组测试结构 , 如果想要突出多级队列的显示, 可以增大 maxRunTime 参数或者 减小时间片数组中元素的大小 50 | 05-21 11:23:57[ARRIVE]进程到达, 进程ID :1001 预计用时: 3(s) 51 | 05-21 11:23:58[ARRIVE]进程到达, 进程ID :1002 预计用时: 4(s) 52 | 05-21 11:23:58[ARRIVE]进程到达, 进程ID :1003 预计用时: 1(s) 53 | 05-21 11:23:58[ARRIVE]进程到达, 进程ID :1004 预计用时: 1(s) 54 | 05-21 11:23:59[ARRIVE]进程到达, 进程ID :1005 预计用时: 5(s) 55 | 05-21 11:23:59[ARRIVE]进程到达, 进程ID :1006 预计用时: 1(s) 56 | 05-21 11:24:00[LACK], 进程ID :1001 耗时: 1(s)添加进程到第 2 级队列 57 | 05-21 11:24:04[LACK], 进程ID :1002 耗时: 1(s)添加进程到第 2 级队列 58 | 05-21 11:24:05[FINISH]执行完毕 进程ID :1003 耗时: 1(s) 59 | 05-21 11:24:06[FINISH]执行完毕 进程ID :1004 耗时: 1(s) 60 | 05-21 11:24:11[LACK], 进程ID :1005 耗时: 1(s)添加进程到第 2 级队列 61 | 05-21 11:24:12[FINISH]执行完毕 进程ID :1006 耗时: 1(s) 62 | 05-21 11:24:14[FINISH]执行完毕 进程ID :1001 耗时: 2(s) 63 | 05-21 11:24:17[LACK], 进程ID :1002 耗时: 2(s)添加进程到第 3 级队列 64 | 05-21 11:24:21[LACK], 进程ID :1005 耗时: 2(s)添加进程到第 3 级队列 65 | 05-21 11:24:22[FINISH]执行完毕 进程ID :1002 耗时: 1(s) 66 | 05-21 11:24:24[FINISH]执行完毕 进程ID :1005 耗时: 2(s) 67 | */ 68 | } 69 | 70 | -------------------------------------------------------------------------------- /页面置换算法/C++/algorithms/LRU.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 侯金科 on 2023/5/6. 3 | // 4 | 5 | #include 6 | 7 | #include "../model/CacheNode.h" 8 | 9 | 10 | 11 | class LRU{ 12 | int capacity;//页容量 13 | CacheNode *head, *tail;//头尾指针 14 | std::map mp; 15 | int times;//次数 16 | int MissingNum;//缺页次数 17 | public: 18 | explicit LRU(int capacity){ 19 | this->capacity = capacity; 20 | head = nullptr; 21 | tail = nullptr; 22 | times = 0; 23 | MissingNum = 0; 24 | } 25 | 26 | int get(int key){ 27 | auto it = mp.find(key);//map::iterator it = mp.find(key); 28 | times ++; 29 | if(it != mp.end()){ 30 | CacheNode *node = it -> second; 31 | remove(node); 32 | setHead(node); 33 | return node -> value; 34 | }else{ 35 | MissingNum++; 36 | set(key, 1); 37 | return -1; 38 | } 39 | } 40 | 41 | void set(int key, int value){ 42 | auto *newNode = new CacheNode(key, value); 43 | if(mp.size() >= capacity){ 44 | auto iter = mp.find(tail -> key); 45 | remove(tail); 46 | mp.erase(iter); 47 | } 48 | setHead(newNode); 49 | mp[key] = newNode; 50 | 51 | } 52 | 53 | void remove(CacheNode *node){ 54 | if(node -> pre != nullptr) 55 | node -> pre -> next = node -> next; 56 | else head = node -> next; 57 | if(node -> next != nullptr) 58 | node -> next -> pre = node -> pre; 59 | else 60 | tail = node -> pre; 61 | } 62 | 63 | void setHead(CacheNode *node){ 64 | node -> next = head; 65 | node -> pre = nullptr; 66 | if(head != nullptr) 67 | head -> pre = node; 68 | head = node; 69 | if(tail == nullptr){ 70 | tail = head; 71 | } 72 | } 73 | 74 | int getTimes() const { 75 | return times; 76 | } 77 | 78 | int getMissingNum() const { 79 | return MissingNum; 80 | } 81 | }; 82 | 83 | /* 84 | int main(){ 85 | 86 | //解决控制条乱码问题 87 | system("chcp 65001"); 88 | LRU *lruCache = new LRU(2); 89 | lruCache -> get(2); 90 | lruCache -> get(1); 91 | cout << lruCache -> get(2) << endl; 92 | lruCache -> get(4); 93 | cout << lruCache -> get(1) << endl; 94 | cout << lruCache -> get(2) << endl; 95 | cout << "缺页次数:" << lruCache->getMissingNum()<getMissingNum()/lruCache->getTimes()<{ 19 | addProcess2Queue(7,5,2); 20 | }).start(); 21 | hrrn.start(); 22 | } 23 | 24 | /* 25 | 下面是一段测试的结果 , 可以看到进程的执行顺序通过判断进程的优先权来进行 26 | 04-10 09:07:06.006[ARRIVE]进程到达, 进程ID :1000 预计用时: 5(s) 27 | 进程ID 优先权 28 | 1000 0.0 29 | 04-10 09:07:06.006[RUNNING]执行进程 进程ID :1000 耗时: 5(s) 进程优先权: 0.0 30 | 04-10 09:07:08.008[ARRIVE]进程到达, 进程ID :1001 预计用时: 2(s) 31 | 04-10 09:07:10.010[ARRIVE]进程到达, 进程ID :1002 预计用时: 5(s) 32 | 进程ID 优先权 33 | 1001 1.543 34 | 1002 0.0 35 | 04-10 09:07:11.011[RUNNING]执行进程 进程ID :1001 耗时: 2(s) 进程优先权: 1.543 36 | 04-10 09:07:12.012[ARRIVE]进程到达, 进程ID :1003 预计用时: 2(s) 37 | 04-10 09:07:13.013[ARRIVE]进程到达, 进程ID :1004 预计用时: 2(s) 38 | 进程ID 优先权 39 | 1004 0.041 40 | 1003 0.0 41 | 1002 0.6208 42 | 04-10 09:07:13.013[RUNNING]执行进程 进程ID :1004 耗时: 2(s) 进程优先权: 0.041 43 | 04-10 09:07:14.014[ARRIVE]进程到达, 进程ID :1005 预计用时: 3(s) 44 | 进程ID 优先权 45 | 1002 1.0222 46 | 1003 0.0 47 | 1005 0.0 48 | 04-10 09:07:15.015[RUNNING]执行进程 进程ID :1002 耗时: 5(s) 进程优先权: 1.0222 49 | 04-10 09:07:16.016[ARRIVE]进程到达, 进程ID :1006 预计用时: 5(s) 50 | 进程ID 优先权 51 | 1005 2.0276666666666667 52 | 1003 0.0 53 | 1006 0.0 54 | 04-10 09:07:20.020[RUNNING]执行进程 进程ID :1005 耗时: 3(s) 进程优先权: 2.0276666666666667 55 | 进程ID 优先权 56 | 1006 1.4146 57 | 1003 0.0 58 | 04-10 09:07:23.023[RUNNING]执行进程 进程ID :1006 耗时: 5(s) 进程优先权: 1.4146 59 | 进程ID 优先权 60 | 1003 8.061 61 | 04-10 09:07:28.028[RUNNING]执行进程 进程ID :1003 耗时: 2(s) 进程优先权: 8.061 62 | */ 63 | 64 | /** 65 | * 添加进程 66 | * @param size 进程的数量 67 | * @param maxRunTime 生成的进程的最大执行时间 68 | * @param maxSleepTime 生成进程的过程中的最大间隔时间 69 | */ 70 | private static void addProcess2Queue(int size,int maxRunTime ,int maxSleepTime){ 71 | for (int i = 0; i < size; i++) { 72 | Process process = new Process(Integer.parseInt(BASE_PID) + i, (int) ((Math.random()*10)%maxRunTime)+1); 73 | hrrn.addProcess(process); 74 | long sleepTime= (int) ((Math.random()*10)%maxSleepTime) +1; 75 | try { 76 | Thread.sleep(1000 * sleepTime); 77 | } catch (InterruptedException e) { 78 | throw new RuntimeException(e); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /进程调度算法/golang/algorithms/Priority.go: -------------------------------------------------------------------------------- 1 | package algorithms 2 | 3 | import ( 4 | "fmt" 5 | . "golang/model" 6 | "time" 7 | ) 8 | 9 | type Priority struct { 10 | cap int 11 | Ready ProcessHeap 12 | Block []Process 13 | Running *Process 14 | } 15 | 16 | // Constructor 构造器 17 | func PriorityConstructor(capacity int) *Priority { 18 | return &Priority{ 19 | cap: capacity, 20 | Ready: ProcessHeap{}, 21 | Block: []Process{}, 22 | Running: nil, 23 | } 24 | } 25 | 26 | func (algo *Priority) Add(process Process) { 27 | fmt.Println(getNowTime()+"\033[35m[Arrive]\033[0m进程到达 , 进程ID :", process.Pid, "进程优先级: ", process.Order, " 预计用时: ", process.RunTime, "(s)") 28 | process.Status = READY 29 | if algo.Ready.Len() >= algo.cap { 30 | process.Status = BLOCK 31 | algo.Block = append(algo.Block, process) 32 | } else { 33 | algo.Ready.Push(process) 34 | } 35 | } 36 | 37 | func (algo *Priority) Start() { 38 | for { 39 | // 每次间歇 40 | time.Sleep(time.Duration(100) * time.Millisecond) 41 | if algo.Ready.Len()+len(algo.Block) > 0 { 42 | algo.execute() 43 | } 44 | } 45 | } 46 | 47 | func (algo *Priority) execute() { 48 | for algo.Running != nil || algo.Ready.Len()+len(algo.Block) > 0 { 49 | if algo.Ready.Len() < 1 { 50 | algo.fromBlock2Ready() 51 | } 52 | // 判断当前进程是否存在 53 | if algo.Running == nil { 54 | //algo.Running = &algo.Ready.Pop().(Process) 不能获取interface{}的地址 55 | run, _ := algo.Ready.Pop().(Process) 56 | algo.Running = &run 57 | time.Sleep(time.Second * time.Duration(algo.Running.RunTime)) 58 | fmt.Println(getNowTime()+"\033[32m[finish]\033[0m执行完毕 , 进程ID :", algo.Running.Pid, " 耗时: ", algo.Running.RunTime, "(s)") 59 | } else { 60 | time.Sleep(time.Second * time.Duration(algo.Running.RunTime)) 61 | fmt.Println(getNowTime()+"\033[32m[finish]\033[0m执行完毕 , 进程ID :", algo.Running.Pid, " 耗时: ", algo.Running.RunTime, "(s)") 62 | } 63 | algo.Running = nil 64 | } 65 | } 66 | 67 | // 把程序从阻塞队列移动到等待队列 68 | func (algo *Priority) fromBlock2Ready() { 69 | for algo.Ready.Len() < algo.cap && len(algo.Block) > 0 { 70 | process := algo.Block[len(algo.Block)-1] 71 | process.Status = READY 72 | //algo.Ready = append(algo.Ready, process) 73 | algo.Ready.Push(process) 74 | algo.Block = algo.Block[:len(algo.Block)-1] // 利用切片 75 | algo.Block = algo.Block[:len(algo.Block)-1] // 利用切片 76 | } 77 | } 78 | 79 | // ProcessHeap 实现优先队列 80 | type ProcessHeap []Process 81 | 82 | func (h ProcessHeap) Len() int { // 重写 Len() 方法 83 | return len(h) 84 | } 85 | 86 | func (h ProcessHeap) Swap(i, j int) { // 重写 Swap() 方法 87 | h[i], h[j] = h[j], h[i] 88 | } 89 | 90 | func (h ProcessHeap) Less(i, j int) bool { // 重写 Less() 方法, 从小到大排序 91 | return h[i].Order > h[j].Order 92 | } 93 | 94 | func (h *ProcessHeap) Push(process interface{}) { 95 | *h = append(*h, process.(Process)) 96 | } 97 | 98 | func (h *ProcessHeap) Pop() interface{} { 99 | old := *h 100 | n := len(old) 101 | x := old[n-1] 102 | *h = old[0 : n-1] 103 | return x 104 | } 105 | -------------------------------------------------------------------------------- /页面置换算法(测试)/README.md: -------------------------------------------------------------------------------- 1 | ## 页面置换算法 2 | 页面的换入换出, 需要启动磁盘的IO 会有较大的开销 , 因此好的页面置换算法应该 ==追求更少的缺页率== 3 | 4 | 5 | 6 | ### 1.最佳置换算法 =>无法实现 7 | 8 | 最佳置换算法(OPT,Optimal): **每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面**,这样可以保证最低的缺页率。 9 | 10 | 最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。 11 | 12 | 操作系统无法提前预判页面访问序列。因此,**最佳置换算法是无法实现的**。 13 | 14 | > 只有当 内存块全部占满并且出现了缺页中断 才会发生 页面置换 15 | 16 | ![](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20210809161659809.png) 17 | 18 | ### 2.先进先出置换算法-FIFO 19 | 20 | 先进先出置换算法(FIFO): **每次选择淘汰的页面是最早进入内存的页面** 21 | 22 | 实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。队列的最大长度取决于系统为进程分配了多少个内存块。 23 | 24 | ![](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20210809161847953.png) 25 | 26 | 那么当我们增加了内存块的个数 : 27 | 28 | ![](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20221224141054903.png) 29 | 30 | 可以发现虽然我们增加了内存块的个数, 缺页中断的 发生次数反而增加了 , 这就是 Belady 异常 31 | 32 | **Belady**异常:**当为进程分配的物理块数增大时,缺页次数不减反增的异常现象。** 33 | 34 | **只有FIFO算法会产生Belady异常**。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,**算法性能差。** 35 | 36 | 37 | 38 | ### 3.最近最久未使用算法-LRU 39 | 40 | 最近最久未使用置换算法(LRU,least recently used): **每次淘汰的页面是最近最久未使用的页面。** 41 | 42 | 实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。 43 | 44 | 当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。 45 | 46 | ![](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20210809162117351.png) 47 | 48 | ### 4.时钟置换算法-NRU 49 | 50 | 最佳置换算法性能最好,但**无法实现**;先进先出置换算法实现简单,**但算法性能差**;最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,**算法开销大**。 51 | 52 | **时钟置换算法**是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,NotRecently Used) 53 | 54 | 简单的CLOCK 算法实现方法: 55 | 56 | 为每个页面设置一个**访问位**,再将内存中的页面都通过链接指针链接成一个**循环队列**。 57 | 58 | 当某页被访问时,其访问位置为1。当需要淘汰一个页面时,只需检查页的访问位。 59 | 60 | - 如果是0,就选择该页换出; 61 | 62 | - 如果是1,则将它置为0,暂不换出,继续检查下一个页面, 63 | 64 | 若第一轮扫描中所有页面都是1,则将这些页面的访问位依次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,**因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)** 65 | 66 | ![](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20210809162337421.png) 67 | 68 | ### 5.改进型的时钟置换算法 69 | 70 | 简单的时钟置换算法仅考虑到一个页面最近是否被访问过。 71 | 72 | 事实上,==如果被淘汰的页面没有被修改过,就不需要执行I/o操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。== 73 | 因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应**考虑页面有没有被修改过**。 74 | 75 | 在其他条件都相同时,应优先淘汰没有修改过的页面,避免I/o操作。这就是改进型的时钟置换算法的思想。修改位=0,表示页面没有被修改过;修改位=1,表示页面被修改过。 76 | 为方便讨论,用==(访问位,修改位)==的形式表示各页面状态。 77 | 78 | - 如(1,1)表示一个页面近期被访问过,且被修改过。 79 | 80 | **算法规则**: 将所有可能被置换的页面排成一个**循环队列** 81 | 第一轮:从当前位置开始扫描到第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位 82 | 第二轮:若第一轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。本轮将所有扫描过的帧访问位设为0 83 | 第三轮:若第二轮扫描失败,则重新扫描,查找第一个(0,0)的帧用于替换。本轮扫描不修改任何标志位 84 | 第四轮:若第三轮扫描失败,则重新扫描,查找第一个(0,1)的帧用于替换。 85 | 由于第二轮已将所有帧的访问位设为0,因此经过第三轮、第四轮扫描一定会有一个帧被选中,因此**改进型CLOCK置换算法选择一个淘汰页面最多会进行四轮扫描** 86 | 87 | ![图示](https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/1082/image-20210809162555604.png) 88 | 89 | > 第一优先级:最近没访问,且没修改的页面 90 | > 第二优先级:最近没访问,但修改过的页面 91 | > 第三优先级:最近访问过,但没修改的页面 92 | > 第四优先级:最近访问过,且修改过的页面 -------------------------------------------------------------------------------- /磁盘调度算法/Java/algorithms/SCAN.java: -------------------------------------------------------------------------------- 1 | package algorithms; 2 | 3 | /** 4 | * @author Discard-001 5 | * @className SCAN 6 | * @date : 2023/05/13/ 17:36 7 | **/ 8 | import java.util.Arrays; 9 | public class SCAN { 10 | private int n; // 磁盘请求数目 11 | private int[] request; // 磁盘请求序列 12 | private int head; // 磁头初始位置 13 | private int direction; // 磁头移动方向,1为增加方向,-1为减少方向 14 | 15 | public SCAN(int n, int[] request, int head) { 16 | this.n = n; 17 | this.request = request; 18 | this.head = head; 19 | Arrays.sort(request); // 对请求序列进行升序排序 20 | //判断走向,可以用二分 21 | for (int i = 0; i < n; i++) { 22 | if (head <= request[i + 1]) { 23 | if (request[i + 1] - head <= head - request[i]) 24 | this.direction = 1; 25 | else this.direction = -1; 26 | break; 27 | } 28 | } 29 | } 30 | 31 | public int schedule() { 32 | int distance = 0; // 磁头移动距离 33 | int seekTime = 0; // 磁头寻道时间 34 | System.out.println("SCAN算法调度过程如下:"); 35 | if (direction == 1) { // 如果磁头向增加方向移动 36 | for (int i = 0; i < n; i++) { 37 | if (request[i] >= head) { // 如果请求在当前磁头位置或之后 38 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 39 | seekTime += distance; // 累加磁头寻道距离 40 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 41 | head = request[i]; // 更新磁头位置 42 | } 43 | } 44 | for (int i = n - 1; i >= 0; i--) { 45 | if (request[i] < head) { // 如果请求在当前磁头位置之前 46 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 47 | seekTime += distance; // 累加磁头寻道距离 48 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 49 | head = request[i]; // 更新磁头位置 50 | } 51 | } 52 | } else if (direction == -1) { // 如果磁头向减少方向移动 53 | for (int i = n - 1; i >= 0; i--) { 54 | if (request[i] <= head) { // 如果请求在当前磁头位置或之前 55 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 56 | seekTime += distance; // 累加磁头寻道距离 57 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 58 | head = request[i]; // 更新磁头位置 59 | } 60 | } 61 | for (int i = 0; i < n; i++) { 62 | if (request[i] > head) { // 如果请求在当前磁头位置之后 63 | distance = Math.abs(request[i] - head); // 计算磁头移动距离 64 | seekTime += distance; // 累加磁头寻道距离 65 | System.out.println("从" + head + "号磁道移动到" + request[i] + "号磁道,移动距离为" + distance); 66 | head = request[i]; // 更新磁头位置 67 | } 68 | } 69 | } 70 | System.out.println("FCFS算法调度结束"); 71 | System.out.println("总移动距离为:" + seekTime); 72 | System.out.println("平均寻道长度为:" + (double) seekTime / n); 73 | return seekTime; 74 | } 75 | } -------------------------------------------------------------------------------- /动态分区匹配算法/Cpp/WF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | //最坏适应算法(Worst-Fit) 3 | // Created by dhrzbz on 2023/5/23. 4 | // 5 | 6 | //最坏适应算法(Worst-Fit) 7 | //该算法会按照⼤⼩顺序查找最⼤的空闲分区,并将进程 8 | //放⼊其中。 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | bool cmp_by_value1(const pair& lhs, const pair& rhs) { 17 | return lhs.second > rhs.second; //改变排序规则,以第二个的值为从大到小排 18 | } 19 | bool cmp_by_value2(const pair& lhs, const pair& rhs) { 20 | return lhs.first < rhs.first; //改变排序规则,以第一个的值为从小到大排 21 | } 22 | class WF 23 | { 24 | private: 25 | 26 | int Max; 27 | vector> p; //存储所剩的空间大小 key:起始地址 value:大小 28 | public: 29 | WF(pair _p) 30 | { 31 | p.push_back(_p); //初始化空间大小 32 | Max = _p.second; //记录空间最大值,防止超出 33 | } 34 | void WF_Add(int n) 35 | { 36 | sort(p.begin(), p.end(), cmp_by_value1);//按value值排序,便于找出第一个可以放下的空闲空间 37 | vector>::iterator it = p.begin();//使用迭代器,便于删去更新空闲空间 38 | for (; it != p.end(); it++) 39 | { 40 | if (n == it->second) //空闲空间==文件大小 直接全部赋予,删除给空闲空间 41 | { 42 | p.erase(it); 43 | return; 44 | } 45 | else if (n <= it->second) //空闲空间>=文件大小 删除旧的,添加新的 46 | { 47 | int j = it->first, k = it->second; 48 | p.erase(it); 49 | p.push_back(pair(j + n, k - n)); 50 | return; 51 | } 52 | } 53 | cout << "分配失败" << endl; //没有合适空间 54 | } 55 | void WF_Free(int n, int length) //释放空间 56 | { 57 | if (n + length > Max) //超出范围 58 | { 59 | cout << "空间超出范围" << endl; 60 | return; 61 | } 62 | for (auto i : p) //判断是否在可释放空间 63 | { 64 | if (i.first <= n && i.second + n >= n) 65 | { 66 | cout << "释放空间有误" << endl; 67 | return; 68 | } 69 | 70 | } 71 | p.push_back(pair(n, length));//将新空闲位置加入 72 | sort(p.begin(), p.end(), cmp_by_value2);//按key值排序,便于合并相邻空闲空间 73 | for (int j = 0, k = 1; k < p.size(); k++) 74 | { 75 | if (p[j].first + p[j].second == p[k].first)//空间相邻,合并 76 | { 77 | vector> ::iterator it = p.begin() + k; 78 | p[j].second += p[k].second; 79 | p.erase(it); 80 | } 81 | else //向后遍历 82 | { 83 | j++; 84 | } 85 | } 86 | } 87 | void Print() //输出剩余可用空间 88 | { 89 | for (auto i : p) 90 | { 91 | cout << i.first << " " << i.second << endl; 92 | } 93 | } 94 | }; 95 | int main() 96 | { 97 | int m, n; 98 | cout << "请输入初始空间大小:"; 99 | cin >> n; 100 | WF ff(pair(0, n)); 101 | for (int i = 0; i < 5; i++) 102 | { 103 | cout << "请选择占有空间(1)或者释放空间(2):" << endl; 104 | cin >> m; 105 | if (m == 1) 106 | { 107 | cout << "请输入文件大小:"; 108 | cin >> n; 109 | cout << endl; 110 | ff.WF_Add(n); 111 | } 112 | else if (m == 2) 113 | { 114 | cout << "请输入释放空间的起始地址及大小" << endl; 115 | int x, y; 116 | cin >> x >> y; 117 | cout << endl; 118 | ff.WF_Free(x, y); 119 | 120 | } 121 | else 122 | cout << "输入错误请重新输入!" << endl; 123 | ff.Print(); 124 | } 125 | 126 | } -------------------------------------------------------------------------------- /动态分区匹配算法/Cpp/BF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | //最佳适应算法(Best - Fit): 3 | // Created by dhrzbz on 2023/5/23. 4 | // 5 | 6 | //最佳适应算法(Best - Fit): 7 | //该算法会按照⼤⼩顺序查找最⼩的能够满⾜需求的空闲分 8 | //区,并将进程放⼊其中。 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | bool cmp_by_value1(const pair& lhs, const pair& rhs) { 17 | return lhs.second < rhs.second; //改变排序规则,以第二个的值为从小到大排 18 | } 19 | bool cmp_by_value2(const pair& lhs, const pair& rhs) { 20 | return lhs.first < rhs.first; //改变排序规则,以第一个的值为从小到大排 21 | } 22 | class BF 23 | { 24 | private: 25 | 26 | int Max; 27 | vector> p; //存储所剩的空间大小 key:起始地址 value:大小 28 | public: 29 | BF(pair _p) 30 | { 31 | p.push_back(_p); //初始化空间大小 32 | Max = _p.second; //记录空间最大值,防止超出 33 | } 34 | void BF_Add(int n) 35 | { 36 | sort(p.begin(), p.end(), cmp_by_value1);//按value值排序,便于找出第一个可以放下的空闲空间 37 | vector>::iterator it = p.begin();//使用迭代器,便于删去更新空闲空间 38 | for (; it != p.end(); it++) 39 | { 40 | if (n == it->second) //空闲空间==文件大小 直接全部赋予,删除给空闲空间 41 | { 42 | p.erase(it); 43 | return; 44 | } 45 | else if (n <= it->second) //空闲空间>=文件大小 删除旧的,添加新的 46 | { 47 | int j = it->first, k = it->second; 48 | p.erase(it); 49 | p.push_back(pair(j + n, k - n)); 50 | return; 51 | } 52 | } 53 | cout << "分配失败" << endl; //没有合适空间 54 | } 55 | void BF_Free(int n, int length) //释放空间 56 | { 57 | if (n + length > Max) //超出范围 58 | { 59 | cout << "空间超出范围" << endl; 60 | return; 61 | } 62 | for (auto i : p) //判断是否在可释放空间 63 | { 64 | if (i.first <= n && i.second + n >= n) 65 | { 66 | cout << "释放空间有误" << endl; 67 | return; 68 | } 69 | 70 | } 71 | p.push_back(pair(n, length));//将新空闲位置加入 72 | sort(p.begin(), p.end(), cmp_by_value2);//按key值排序,便于合并相邻空闲空间 73 | for (int j = 0, k = 1; k < p.size(); k++) 74 | { 75 | if (p[j].first + p[j].second == p[k].first)//空间相邻,合并 76 | { 77 | vector> ::iterator it = p.begin() + k; 78 | p[j].second += p[k].second; 79 | p.erase(it); 80 | } 81 | else //向后遍历 82 | { 83 | j++; 84 | } 85 | } 86 | } 87 | void Print() //输出剩余可用空间 88 | { 89 | for (auto i : p) 90 | { 91 | cout << i.first << " " << i.second << endl; 92 | } 93 | } 94 | }; 95 | int main() 96 | { 97 | int m, n; 98 | cout << "请输入初始空间大小:"; 99 | cin >> n; 100 | BF ff(pair(0, n)); 101 | for (int i = 0; i < 5; i++) 102 | { 103 | cout << "请选择占有空间(1)或者释放空间(2):" << endl; 104 | cin >> m; 105 | if (m == 1) 106 | { 107 | cout << "请输入文件大小:"; 108 | cin >> n; 109 | cout << endl; 110 | ff.BF_Add(n); 111 | } 112 | else if (m == 2) 113 | { 114 | cout << "请输入释放空间的起始地址及大小" << endl; 115 | int x, y; 116 | cin >> x >> y; 117 | cout << endl; 118 | ff.BF_Free(x, y); 119 | 120 | } 121 | else 122 | cout << "输入错误请重新输入!" << endl; 123 | ff.Print(); 124 | } 125 | 126 | } -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/sample/QFExample.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.sample; 2 | 3 | import com.os.dynamicmatching.algorithms.QF; 4 | import com.os.dynamicmatching.util.RandomTestUtil; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author adorabled4 10 | * @className QFExample 11 | * @date : 2023-5-16 19:26:06 12 | **/ 13 | public class QFExample { 14 | 15 | public static void main(String[] args) { 16 | testQF(1024, 10); 17 | } 18 | 19 | /** 20 | * 测试 动态分区匹配算法 仅仅测试当前算法的执行方式以及内容 21 | * 22 | * @param cap frame容量 23 | * @param processSize 进程的个数 24 | */ 25 | static void testQF(int cap, int processSize) { 26 | List timeCounts = RandomTestUtil.testDynamicMatching(cap, processSize, QF.class); 27 | long timeCount = 0; 28 | for (Long count : timeCounts) { 29 | timeCount += count; 30 | } 31 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 分配总耗时: " + timeCount + "(ns)"); 32 | } 33 | 34 | /* 35 | 下面是一组测试结果 36 | 2023-05--16 07:34:45 [ADD]添加进程: 1001 驻留时间: 10(s) 需要Frame: 100 37 | 2023-05--16 07:34:45 [ALLOCATE]为进程1001分配, 大小: 100 起始frame: 0 本次分配耗时 : 2088(ns) 38 | 2023-05--16 07:34:47 [ADD]添加进程: 1002 驻留时间: 10(s) 需要Frame: 130 39 | 2023-05--16 07:34:47 [ALLOCATE]为进程1002分配, 大小: 130 起始frame: 0 本次分配耗时 : 80(ns) 40 | 2023-05--16 07:34:49 [ADD]添加进程: 1003 驻留时间: 2(s) 需要Frame: 50 41 | 2023-05--16 07:34:49 [ALLOCATE]为进程1003分配, 大小: 50 起始frame: 0 本次分配耗时 : 81(ns) 42 | 2023-05--16 07:34:51 [ADD]添加进程: 1004 驻留时间: 2(s) 需要Frame: 110 43 | 2023-05--16 07:34:51 [ALLOCATE]为进程1004分配, 大小: 110 起始frame: 0 本次分配耗时 : 201(ns) 44 | 2023-05--16 07:34:51 [GC]回收进程 1003 ,大小: 50 45 | 2023-05--16 07:34:53 [ADD]添加进程: 1005 驻留时间: 7(s) 需要Frame: 120 46 | 2023-05--16 07:34:53 [ALLOCATE]为进程1005分配, 大小: 120 起始frame: 0 本次分配耗时 : 60(ns) 47 | 2023-05--16 07:34:53 [GC]回收进程 1004 ,大小: 110 48 | 2023-05--16 07:34:55 [GC]回收进程 1001 ,大小: 100 49 | 2023-05--16 07:34:55 [ADD]添加进程: 1006 驻留时间: 7(s) 需要Frame: 20 50 | 2023-05--16 07:34:55 [ALLOCATE]为进程1006分配, 大小: 20 起始frame: 0 本次分配耗时 : 89(ns) 51 | 2023-05--16 07:34:57 [GC]回收进程 1002 ,大小: 130 52 | 2023-05--16 07:34:57 [ADD]添加进程: 1007 驻留时间: 4(s) 需要Frame: 150 53 | 2023-05--16 07:34:57 [ALLOCATE]为进程1007分配, 大小: 150 起始frame: 0 本次分配耗时 : 67(ns) 54 | 2023-05--16 07:34:59 [ADD]添加进程: 1008 驻留时间: 2(s) 需要Frame: 30 55 | 2023-05--16 07:34:59 [ALLOCATE]为进程1008分配, 大小: 30 起始frame: 0 本次分配耗时 : 61(ns) 56 | 2023-05--16 07:35:00 [GC]回收进程 1005 ,大小: 120 57 | 2023-05--16 07:35:01 [GC]回收进程 1008 ,大小: 30 58 | 2023-05--16 07:35:01 [GC]回收进程 1007 ,大小: 150 59 | 2023-05--16 07:35:01 [ADD]添加进程: 1009 驻留时间: 9(s) 需要Frame: 130 60 | 2023-05--16 07:35:01 [ALLOCATE]为进程1009分配, 大小: 130 起始frame: 0 本次分配耗时 : 64(ns) 61 | 2023-05--16 07:35:02 [GC]回收进程 1006 ,大小: 20 62 | 2023-05--16 07:35:03 [ADD]添加进程: 1010 驻留时间: 10(s) 需要Frame: 80 63 | 2023-05--16 07:35:03 [ALLOCATE]为进程1010分配, 大小: 80 起始frame: 0 本次分配耗时 : 58(ns) 64 | [测试结束] 分配总耗时: 2849(ns) 65 | 2023-05--16 07:35:10 [GC]回收进程 1009 ,大小: 130 66 | 2023-05--16 07:35:13 [GC]回收进程 1010 ,大小: 80 67 | 68 | 进程已结束,退出代码0 69 | 70 | */ 71 | } 72 | -------------------------------------------------------------------------------- /页面置换算法(测试)/Java/com/dhx/algorithms/lru/LRUCache.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms.lru; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author dhx_ 7 | * @className LRUCache 8 | * @date : 2023/02/17/ 19:26 9 | **/ 10 | public class LRUCache { 11 | 12 | /** 13 | * key -> Node(key, val) 14 | */ 15 | private HashMap map; 16 | 17 | /** 18 | * Node(k1, v1) <-> Node(k2, v2)... 19 | */ 20 | private DoubleList cache; 21 | 22 | 23 | /** 24 | * max capacity 25 | */ 26 | private int cap; 27 | 28 | /** 29 | * default capacity 30 | */ 31 | public static final int DEFAULT_CAPACITY=10; 32 | 33 | /** 34 | * 35 | * @param capacity LRU容量 36 | */ 37 | public LRUCache(int capacity) { 38 | if(capacity<0){ 39 | this.cap=DEFAULT_CAPACITY; 40 | }else{ 41 | this.cap = capacity; 42 | } 43 | map = new HashMap<>(); 44 | cache = new DoubleList(); 45 | } 46 | 47 | /** 48 | * 将某个 key 提升为最近使用的 49 | * @param key 50 | */ 51 | private void makeRecently(int key) { 52 | Node x = map.get(key); 53 | // 先从链表中删除这个节点 54 | cache.remove(x); 55 | // 重新插到队尾 56 | cache.addLast(x); 57 | } 58 | 59 | /** 60 | * 添加最近使用的元素 61 | * @param key 62 | * @param val 63 | */ 64 | private void addRecently(int key, int val) { 65 | Node x = new Node(key, val); 66 | // 链表尾部就是最近使用的元素 67 | cache.addLast(x); 68 | // 别忘了在 map 中添加 key 的映射 69 | map.put(key, x); 70 | } 71 | 72 | /** 73 | * 删除某一个 key 74 | * @param key 75 | */ 76 | private void deleteKey(int key) { 77 | Node x = map.get(key); 78 | // 从链表中删除 79 | cache.remove(x); 80 | // 从 map 中删除 81 | map.remove(key); 82 | } 83 | 84 | /** 85 | * 删除最久未使用的元素 86 | */ 87 | private void removeLeastRecently() { 88 | // 链表头部的第一个元素就是最久未使用的 89 | Node deletedNode = cache.removeFirst(); 90 | // 同时别忘了从 map 中删除它的 key 91 | int deletedKey = deletedNode.key; 92 | map.remove(deletedKey); 93 | } 94 | 95 | /** 96 | * 获取key对应的value 97 | * @param key 98 | * @return 99 | */ 100 | public int get(int key) { 101 | if (!map.containsKey(key)) { 102 | return -1; 103 | } 104 | // 将该数据提升为最近使用的 105 | makeRecently(key); 106 | return map.get(key).val; 107 | } 108 | 109 | /** 110 | * 向LRU中添加数据 111 | * @param key 112 | * @param val 113 | */ 114 | public void put(int key,int val){ 115 | if (map.containsKey(key)) { 116 | // 删除旧的数据 117 | deleteKey(key); 118 | // 新插入的数据为最近使用的数据 119 | addRecently(key, val); 120 | return; 121 | } 122 | if (cap == cache.size()) { 123 | // 删除最久未使用的元素 124 | removeLeastRecently(); 125 | } 126 | // 添加为最近使用的元素 127 | addRecently(key, val); 128 | } 129 | 130 | @Override 131 | public String toString() { 132 | return "LRUCache{" + 133 | "values=" + map + 134 | '}'; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/util/AlgorithmUtil.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.util; 2 | 3 | import com.os.dynamicmatching.model.DMConstant; 4 | import com.os.dynamicmatching.model.Frame; 5 | import com.os.dynamicmatching.model.FramePartitionNode; 6 | import com.os.dynamicmatching.model.Process; 7 | 8 | import java.util.*; 9 | 10 | /** 11 | * @author adorabled4 12 | * @className AlgorithmUtil 13 | * @date : 2023/05/15/ 12:09 14 | **/ 15 | public class AlgorithmUtil { 16 | 17 | 18 | /** 19 | * 查找当前内存分区情况 , 返回连续的空闲的列表 20 | * 21 | * @param mem 22 | * @return 返回map列表 , 映射关系为 : frameSize : int[] , 数组中存储起始下标 23 | */ 24 | public static List> searchPartition(List mem) { 25 | ArrayList> results = new ArrayList<>(); 26 | for (int i = 0; i < mem.size(); i++) { 27 | if (mem.get(i).getStatus() == DMConstant.FREE) { 28 | HashMap map = new HashMap<>(); 29 | int j = i; 30 | while (j < mem.size() && mem.get(j).getStatus() == DMConstant.FREE) { 31 | j++; 32 | } 33 | map.put(j - i , new int[]{i, j-1}); 34 | results.add(map); 35 | i = j+1; 36 | } 37 | } 38 | results.sort((o1, o2) -> o2.keySet().iterator().next() - o2.keySet().iterator().next()); 39 | return results; 40 | } 41 | 42 | /** 43 | * 分配标记内存 并 执行 44 | * @param startFrame 45 | * @param mem 46 | * @param process 47 | * @param startTime 48 | */ 49 | public static void allocateMem(int startFrame, List mem, Process process, long startTime) { 50 | // 标记内存为已使用 51 | for (int j = startFrame; j < startFrame + process.getFrameSize(); j++) { 52 | mem.get(j).setStatus(DMConstant.USED); 53 | } 54 | process.setStatus(Process.READY); 55 | long timeConsume = (System.nanoTime() - startTime) / 1000; 56 | process.setTimeConsume(timeConsume); 57 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[33m\u001B[1m[ALLOCATE]\u001B[0m为进程" + process.getPID() + "分配, 大小: " + process.getFrameSize() + " 起始frame: " + startFrame + " 本次分配耗时 : " + process.getTimeConsume() + "(ns)"); 58 | // 执行进程 59 | RandomTestUtil.runAndMemCollect(process, startFrame, mem); 60 | } 61 | 62 | /** 63 | * 分配标记内存 并 执行 64 | * @param startFrame 65 | * @param node 66 | * @param process 67 | * @param startTime 68 | */ 69 | public static void allocateMem(int startFrame, FramePartitionNode node, Process process, long startTime) { 70 | List mem = node.getMem(); 71 | // 标记内存为已使用 72 | for (int j = startFrame; j < startFrame + process.getFrameSize(); j++) { 73 | mem.get(j).setStatus(DMConstant.USED); 74 | } 75 | process.setStatus(Process.READY); 76 | long timeConsume = (System.nanoTime() - startTime) / 1000; 77 | process.setTimeConsume(timeConsume); 78 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[33m\u001B[1m[ALLOCATE]\u001B[0m为进程" + process.getPID() + "分配, 大小: " + process.getFrameSize() + " 起始frame: " + startFrame + " 本次分配耗时 : " + process.getTimeConsume() + "(ns)"); 79 | // 执行进程 80 | RandomTestUtil.runAndMemCollect(process, startFrame, node); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/model/Process.java: -------------------------------------------------------------------------------- 1 | package com.dhx.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author dhx_ 7 | * @className 进程 8 | * @date : 2023/03/27/ 21:42 9 | **/ 10 | public class Process { 11 | 12 | /** 13 | * 进程ID 14 | */ 15 | int PID; 16 | 17 | /** 18 | * 进程状态 19 | */ 20 | int status; 21 | 22 | /** 23 | * 进程优先级 24 | */ 25 | int order; 26 | 27 | /** 28 | * 执行时间 29 | */ 30 | long runTime; 31 | 32 | /** 33 | * 到达时间(时刻) 34 | */ 35 | Date arriveTime; 36 | 37 | /** 38 | * 结束时间(时刻) 39 | */ 40 | Date finishTime; 41 | 42 | /** 43 | * 周转时间 : 周转时间=结束时间-到达时间 44 | */ 45 | long cycleTime; 46 | 47 | /** 48 | * 平均周转时间 : 平均周转时间=周转时间/运行时间 49 | */ 50 | long aveCycleTime; 51 | 52 | /** 53 | * HRRN 算法的优先权 54 | */ 55 | double preemption; 56 | 57 | public double getPreemption() { 58 | return preemption; 59 | } 60 | 61 | public void setPreemption(double preemption) { 62 | this.preemption = preemption; 63 | } 64 | 65 | public Process(int PID , int runTime){ 66 | this.PID=PID; 67 | this.runTime=runTime; // 设置进程需要的执行时间 68 | order=DEFAULT_ORDER; 69 | status=READY; // 此处模拟进程分配 , 默认初始进程状态为READY 70 | } 71 | 72 | /** 73 | * 进程就绪 74 | */ 75 | public static final int READY=1; 76 | 77 | /** 78 | * 进程阻塞 79 | */ 80 | public static final int BLOCK=2; 81 | 82 | /** 83 | * 执行 84 | */ 85 | public static final int RUNNING=3; 86 | 87 | /** 88 | * 默认进程优先级 89 | */ 90 | public static final int DEFAULT_ORDER=0; 91 | 92 | 93 | public int getPID() { 94 | return PID; 95 | } 96 | 97 | 98 | public int getStatus() { 99 | return status; 100 | } 101 | 102 | public void setStatus(int status) { 103 | this.status = status; 104 | } 105 | 106 | public int getOrder() { 107 | return order; 108 | } 109 | 110 | public void setOrder(int order) { 111 | this.order = order; 112 | } 113 | 114 | public long getRunTime() { 115 | return runTime; 116 | } 117 | 118 | public void setRunTime(long runTime) { 119 | this.runTime = runTime; 120 | } 121 | 122 | public Date getArriveTime() { 123 | return arriveTime; 124 | } 125 | 126 | public void setArriveTime(Date arriveTime) { 127 | this.arriveTime = arriveTime; 128 | } 129 | 130 | public Date getFinishTime() { 131 | return finishTime; 132 | } 133 | 134 | public void setFinishTime(Date finishTime) { 135 | this.finishTime = finishTime; 136 | } 137 | 138 | public long getCycleTime() { 139 | return cycleTime; 140 | } 141 | 142 | public void setCycleTime(long cycleTime) { 143 | this.cycleTime = cycleTime; 144 | } 145 | 146 | public long getAveCycleTime() { 147 | return aveCycleTime; 148 | } 149 | 150 | public void setAveCycleTime(long aveCycleTime) { 151 | this.aveCycleTime = aveCycleTime; 152 | } 153 | 154 | @Override 155 | public String toString() { 156 | return "Process{" + 157 | "PID=" + PID + 158 | ", status=" + status + 159 | ", order=" + order + 160 | '}'; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /进程调度算法/Python/MLFQ.py: -------------------------------------------------------------------------------- 1 | #丁士钦 2023.05.19 MLFQ算法 2 | 3 | 4 | import heapq 5 | 6 | 7 | class Process: 8 | def __init__(self, name, arrive_time, serve_time, priority=0): 9 | self.name = name # 进程名 10 | self.arrive_time = arrive_time # 进程到达时间 11 | self.serve_time = serve_time # 进程服务时间 12 | self.left_serve_time = serve_time # 进程剩余服务时间,初始化为服务时间 13 | self.finish_time = 0 # 进程完成时间,初始化为 0 14 | self.cycling_time = 0 # 进程周转时间,初始化为 0 15 | self.w_cycling_time = 0 # 进程带权周转时间,初始化为 0 16 | self.priority = priority # 进程优先级,默认为 0 17 | 18 | def __lt__(self, other): 19 | return self.arrive_time < other.arrive_time # 比较两个进程到达时间的先后顺序 20 | 21 | def execute(self, time_slice=None): 22 | if time_slice is None or self.left_serve_time <= time_slice: 23 | # 进程完成执行 24 | self.finish_time = max(self.arrive_time + self.serve_time, self.finish_time) 25 | self.cycling_time = self.finish_time - self.arrive_time 26 | self.w_cycling_time = self.cycling_time / self.serve_time 27 | self.left_serve_time = 0 28 | return True 29 | else: 30 | # 进程需要继续执行 31 | self.left_serve_time -= time_slice 32 | return False 33 | 34 | 35 | class PriorityQueue: 36 | def __init__(self): 37 | self.heap = [] # 在初始时创建一个空堆 38 | self.index = 0 # 初始化堆的索引为 0 39 | 40 | def size(self): 41 | # 返回堆中元素的数量 42 | return len(self.heap) 43 | 44 | def add(self, priority, item): 45 | # 将一个元素添加到堆中 46 | heapq.heappush(self.heap, (priority, self.index, item)) 47 | self.index += 1 48 | 49 | def get(self): 50 | # 获取堆中优先级最高的元素 51 | if self.heap: 52 | return heapq.heappop(self.heap)[-1] 53 | else: 54 | return None 55 | 56 | 57 | class RR: 58 | def __init__(self, process_dict, time_slice): 59 | self.process_dict = process_dict 60 | self.time_slice = time_slice 61 | 62 | def scheduling(self): 63 | queue = PriorityQueue() 64 | for process in self.process_dict.values(): 65 | queue.add(process.arrive_time, process) 66 | 67 | total_time = 0 68 | while queue.size() > 0: 69 | process = queue.get() 70 | if not process.execute(self.time_slice): 71 | # 进程需要继续执行,添加回队列 72 | queue.add(total_time, process) 73 | total_time += self.time_slice 74 | 75 | 76 | class MultilevelFeedbackQueue: 77 | def __init__(self, queue_list, time_slices): 78 | self.queue_list = queue_list 79 | self.time_slices = time_slices 80 | 81 | def scheduling(self): 82 | for i in range(len(self.queue_list)): 83 | current_queue = self.queue_list[i] 84 | time_slice = self.time_slices[i] 85 | 86 | while current_queue.size() > 0: 87 | process = current_queue.get() 88 | if not process.execute(time_slice): 89 | # 进程需要移动到下一个队列 90 | if i == len(self.queue_list) - 1: 91 | # 最后一个队列,使用具有指定时间片的RR调度 92 | rr = RR({process.name: process}, time_slice) 93 | rr.scheduling() 94 | else: 95 | # 将进程添加到下一个队列的末尾 96 | self.queue_list[i + 1].add(process.priority, process) 97 | 98 | else: 99 | # 进程已完成执行,从队列中删除 100 | current_queue.get() 101 | 102 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/algorithms/FCFS.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms; 2 | 3 | import com.dhx.model.Process; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.LinkedList; 8 | 9 | /** 10 | * @author dhx_ 11 | * @className FCFS first-come first-served 先来先服务算法 12 | * @date : 2023/03/27/ 21:45 13 | **/ 14 | public class FCFS { 15 | 16 | /** 17 | * 就绪队列最大容量 18 | */ 19 | int cap; 20 | 21 | /** 22 | * 累计的程序数量 23 | */ 24 | int totalProcessNum; 25 | 26 | /** 27 | * 已经执行的程序数量 28 | */ 29 | int completedNum; 30 | /** 31 | * 就绪队列 32 | */ 33 | Process running; 34 | /** 35 | * 就绪队列 : 每次从就绪队列中找到一个进程来执行 36 | */ 37 | LinkedList readyQueue; 38 | 39 | /** 40 | * 阻塞队列 41 | */ 42 | LinkedList blockQueue; 43 | 44 | /** 45 | * 添加进程 46 | * 47 | * @param p 进程 48 | */ 49 | public void addProcess(Process p) { 50 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()) + 51 | "\33[35;1m[ARRIVE]进程到达\33[0m, 进程ID :" + p.getPID() + " 预计用时: " + p.getRunTime() + "(s)"); 52 | p.setStatus(Process.READY); 53 | p.setArriveTime(new Date()); // 设置到达时间 54 | // 如果当前的就绪队列已满, 那么把程序添加到阻塞队列(实际上的作用相当于挂载:suspend) 55 | if (readyQueue.size() >= cap) { 56 | p.setStatus(Process.BLOCK); 57 | blockQueue.add(p); 58 | return; 59 | } 60 | readyQueue.add(p); 61 | totalProcessNum++; 62 | } 63 | 64 | /** 65 | * 执行进程 66 | */ 67 | public void executeProcess() { 68 | while (running == null && (readyQueue.size() > 0 || blockQueue.size() > 0)) { 69 | if (readyQueue.size() < 1) { 70 | fromBlock2Ready(); 71 | } 72 | running = readyQueue.poll(); 73 | try { 74 | Thread.sleep(running.getRunTime() * 1000); 75 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()) + 76 | "\33[92;1m[FINISH]执行完毕\33[0m 进程ID :" + running.getPID() + 77 | "\t耗时: " + running.getRunTime() + "(s)"); 78 | } catch (InterruptedException e) { 79 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss") + "执行进程出现异常"); 80 | } 81 | running = null; 82 | } 83 | completedNum++; 84 | } 85 | 86 | /** 87 | * 把程序从阻塞队列移动到等待队列 88 | */ 89 | private void fromBlock2Ready() { 90 | if (blockQueue.size() == 0) { 91 | return; 92 | } 93 | while (blockQueue.size() > 0 && readyQueue.size() < cap) { 94 | Process process = readyQueue.poll(); 95 | if (process != null) { 96 | process.setStatus(Process.READY); 97 | readyQueue.add(process); 98 | } 99 | } 100 | } 101 | 102 | /** 103 | * 开始执行 104 | */ 105 | public void start() { 106 | while (true) { 107 | try { 108 | Thread.sleep(100); 109 | } catch (InterruptedException e) { 110 | throw new RuntimeException(e); 111 | } 112 | if (readyQueue.size() > 0 || blockQueue.size() > 0) { 113 | executeProcess(); 114 | } 115 | } 116 | } 117 | 118 | public FCFS(int capacity) { 119 | this.cap = capacity; 120 | readyQueue = new LinkedList<>(); 121 | blockQueue = new LinkedList<>(); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/algorithms/SJF.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms; 2 | 3 | import com.dhx.model.Process; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.LinkedList; 8 | import java.util.PriorityQueue; 9 | 10 | /** 11 | * @author dhx_ 12 | * @className SJF : 短进程优先 , 底层采用 堆 存储, 新的进程入队的时候通过预计的执行时间来排序 13 | * @date : 2023/04/07/ 13:46 14 | **/ 15 | public class SJF { 16 | 17 | /** 18 | * 就绪队列最大容量 19 | */ 20 | int cap; 21 | 22 | /** 23 | * 累计的程序数量 24 | */ 25 | int totalProcessNum; 26 | 27 | /** 28 | * 已经执行的程序数量 29 | */ 30 | int completedNum; 31 | /** 32 | * 就绪队列 33 | */ 34 | Process running; 35 | /** 36 | * 就绪队列 : 每次从就绪队列中找到一个进程来执行 37 | */ 38 | PriorityQueue readyQueue; 39 | 40 | /** 41 | * 阻塞队列 42 | */ 43 | LinkedList blockQueue; 44 | 45 | /** 46 | * 添加进程 47 | * @param p 进程 48 | */ 49 | public void addProcess(Process p){ 50 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date())+ 51 | "\33[35;1m[ARRIVE]进程到达\33[0m, 进程ID :"+ p.getPID() +" 预计用时: "+p.getRunTime() +"(s)"); 52 | p.setStatus(Process.READY); 53 | p.setArriveTime(new Date()); // 设置到达时间 54 | // 如果当前的就绪队列已满, 那么把程序添加到阻塞队列(实际上的作用相当于挂载:suspend) 55 | if(readyQueue.size()>=cap){ 56 | p.setStatus(Process.BLOCK); 57 | blockQueue.add(p); 58 | return ; 59 | } 60 | readyQueue.add(p); 61 | totalProcessNum++; 62 | } 63 | 64 | /** 65 | * 执行进程 66 | */ 67 | private void executeProcess(){ 68 | while(running==null && (readyQueue.size()>0 || blockQueue.size()>0)){ 69 | if(readyQueue.size()<1){ 70 | fromBlock2Ready(); 71 | } 72 | running=readyQueue.poll(); 73 | try{ 74 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date())+ 75 | "\33[92;1m[RUNNING]执行进程\33[0m 进程ID :"+ running.getPID()+ 76 | "\t耗时: "+running.getRunTime()+"(s)"); 77 | Thread.sleep(running.getRunTime()*1000); 78 | }catch (InterruptedException e) { 79 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss") + "执行进程出现异常"); 80 | } 81 | running=null; 82 | } 83 | completedNum++; 84 | } 85 | 86 | /** 87 | * 把程序从阻塞队列移动到等待队列 88 | */ 89 | private void fromBlock2Ready(){ 90 | if(blockQueue.size() == 0){ 91 | return ; 92 | } 93 | while(blockQueue.size()>0 && readyQueue.size()0 || blockQueue.size()>0){ 113 | executeProcess(); 114 | } 115 | } 116 | } 117 | 118 | public SJF(int capacity){ 119 | this.cap =capacity; 120 | readyQueue=new PriorityQueue<>((o1,o2)-> (int) (o1.getRunTime()-o2.getRunTime())); 121 | blockQueue=new LinkedList<>(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /动态分区匹配算法/Cpp/QF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | //快速适应算法(Quick-Fit) 3 | // Created by dhrzbz on 2023/5/24 4 | // 5 | 6 | //快速适应算法(Quick - Fit): 7 | //该算法是⼀个改进的最佳适应算法,它会为不同⼤⼩的 8 | //分区维护⼀个独⽴的链表,以便更快地查找适合的空闲分区。 9 | 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | 15 | class QF 16 | { 17 | private: 18 | int Max; //最多级数 19 | vector q; //存储当前位置的可存空间大小 20 | vector> p; //存储可用空间的首地址 21 | public: 22 | QF(int n) //初始化 23 | { 24 | int i = 1; 25 | Max = n; 26 | for (int j = 0; j < Max - 1; j++) //预留一个位置 27 | { 28 | if (j == 0) //第一个两个空间方便合成大空间 29 | { 30 | i = i << 10; //最小1kB 31 | q.push_back(i); //可存空间大小 32 | vector v; 33 | v.push_back(0); 34 | v.push_back(i); 35 | p.push_back(v); //存储可用空间的首地址 36 | } 37 | else 38 | { 39 | i = i << 1; 40 | q.push_back(i); //可存空间大小 41 | vector v; 42 | v.push_back(i); 43 | p.push_back(v); //存储可用空间的首地址 44 | } 45 | } 46 | q.push_back(i << 1); //最后一个用来存储全部合成的大空间 47 | vector v; 48 | p.push_back(v); 49 | } 50 | bool Add(int n) //遍历来寻找合适空间 51 | { 52 | for (int i = 0; i < Max; i++) //找到合适空间,直接分配 53 | { 54 | if (q[i] >= n && q[i] / 2 < n) 55 | { 56 | if (p[i].empty() != true) 57 | { 58 | vector ::iterator it = p[i].begin(); 59 | p[i].erase(it); 60 | return true; 61 | } 62 | } 63 | else if (q[i] / 2 >= n && i > 0)//找不到合适空间,拆分更高一级的为较小空间存储 64 | { 65 | vector ::iterator it = p[i].begin(); 66 | p[i].erase(it); 67 | p[i - 1].push_back(q[i] + q[i - 1]); 68 | return true; 69 | } 70 | } 71 | return false; 72 | } 73 | void QF_Add(int n) //分配空间 74 | { 75 | if (Add(n)) //第一次尝试 76 | return; 77 | for (int i = 0; i < Max; i++) //合并空间再次尝试 78 | { 79 | if (p[i].size() >= 2) 80 | { 81 | vector ::iterator it = p[i].end() - 1; 82 | vector ::iterator it1 = it - 1; 83 | p[i].erase(it); 84 | int k = *it1; 85 | p[i].erase(it1); 86 | vector ::iterator it2 = p[i + 1].begin(); 87 | p[i + 1].insert(it2, k); 88 | } 89 | if (Add(n)) //再次尝试 90 | return; 91 | } 92 | cout << "空间不够,放入失败" << endl;//合并后仍不够,放入失败 93 | return; 94 | } 95 | void QF_Free(int n, int length) //释放空间 n 起始位置 96 | { 97 | if (!(n == 0 || n % 1024 == 0)) //判断起始位置是否正确 98 | { 99 | cout << "输入有误" << endl; 100 | return; 101 | } 102 | for (int i = 0; i < Max; i++) //找到合适位置释放,并放入该数组合适位置(按从小到大排) 103 | { 104 | if (q[i] >= length) 105 | { 106 | for (vector ::iterator it = p[i].begin(); it != p[i].end(); it++) 107 | { 108 | if (*it > n) //在中间或者开头 109 | { 110 | p[i].insert(it, n); 111 | return; 112 | } 113 | } 114 | p[i].push_back(n); //n为最大 115 | return; 116 | } 117 | } 118 | return; 119 | } 120 | void Print() //输出剩余可用空间 121 | { 122 | int k = 0; 123 | for (vector> ::iterator i = p.begin(); i != p.end(); i++, k++) 124 | { 125 | 126 | if (i->empty()) //该大小空间无可用,不输出 127 | continue; 128 | cout << q[k] << " "; 129 | for (vector ::iterator j = i->begin(); j != i->end(); j++) 130 | { 131 | cout << *j << " "; 132 | } 133 | cout << endl; 134 | } 135 | } 136 | }; 137 | int main() 138 | { 139 | 140 | QF qf = QF(5); //初始化为5级 141 | qf.Print(); //输出可用空间 142 | cout << endl; 143 | qf.QF_Add(1000); //占用1000大小空间 144 | qf.Print(); //输出可用空间 145 | cout << endl; 146 | qf.QF_Free(0, 1000); //释放0,1000位置大小空间 147 | qf.Print(); //输出可用空间 148 | cout << endl; 149 | qf.QF_Add(16000); //占用16000大小空间 150 | qf.Print(); //输出可用空间 151 | } -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/sample/FFExample.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.sample; 2 | 3 | import com.os.dynamicmatching.algorithms.FF; 4 | import com.os.dynamicmatching.model.Process; 5 | import com.os.dynamicmatching.util.RandomTestUtil; 6 | import com.os.dynamicmatching.util.TimeUtil; 7 | import com.sun.tools.javac.Main; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.concurrent.CompletableFuture; 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.FutureTask; 14 | 15 | /** 16 | * @author adorabled4 17 | * @className FFExample 18 | * @date : 2023/05/13/ 15:45 19 | **/ 20 | public class FFExample { 21 | 22 | public static void main(String[] args) { 23 | testFF(500, 10); 24 | } 25 | 26 | /** 27 | * 测试 动态分区匹配算法 仅仅测试当前算法的执行方式以及内容 28 | * 29 | * @param cap frame容量 30 | * @param processSize 进程的个数 31 | */ 32 | static void testFF(int cap, int processSize) { 33 | List timeCounts = RandomTestUtil.testDynamicMatching(cap, processSize, FF.class); 34 | long timeCount = 0; 35 | for (Long count : timeCounts) { 36 | timeCount += count; 37 | } 38 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 分配总耗时: " + timeCount + "(ms)"); 39 | } 40 | 41 | /* 42 | 下面是一组测试结果 43 | 2023-05--14 10:01:07 [ADD]添加进程: 1001 驻留时间: 1 需要Frame: 50 44 | 2023-05--14 10:01:07 [ALLOCATE]为进程1001分配, 大小: 50 起始frame: 0 本次分配耗时 : 42(ms) 45 | 2023-05--14 10:01:08 [GC]回收进程 1001 ,大小: 50 46 | 2023-05--14 10:01:09 [ADD]添加进程: 1002 驻留时间: 3 需要Frame: 170 47 | 2023-05--14 10:01:09 [ALLOCATE]为进程1002分配, 大小: 170 起始frame: 0 本次分配耗时 : 82(ms) 48 | 2023-05--14 10:01:11 [ADD]添加进程: 1003 驻留时间: 9 需要Frame: 70 49 | 2023-05--14 10:01:11 [ALLOCATE]为进程1003分配, 大小: 70 起始frame: 170 本次分配耗时 : 37(ms) 50 | 2023-05--14 10:01:12 [GC]回收进程 1002 ,大小: 170 51 | 2023-05--14 10:01:13 [ADD]添加进程: 1004 驻留时间: 1 需要Frame: 80 52 | 2023-05--14 10:01:13 [ALLOCATE]为进程1004分配, 大小: 80 起始frame: 0 本次分配耗时 : 20(ms) 53 | 2023-05--14 10:01:14 [GC]回收进程 1004 ,大小: 80 54 | 2023-05--14 10:01:15 [ADD]添加进程: 1005 驻留时间: 9 需要Frame: 120 55 | 2023-05--14 10:01:15 [ALLOCATE]为进程1005分配, 大小: 120 起始frame: 0 本次分配耗时 : 30(ms) 56 | 2023-05--14 10:01:17 [ADD]添加进程: 1006 驻留时间: 10 需要Frame: 190 57 | 2023-05--14 10:01:17 [ALLOCATE]为进程1006分配, 大小: 190 起始frame: 240 本次分配耗时 : 212(ms) 58 | 2023-05--14 10:01:19 [ADD]添加进程: 1007 驻留时间: 1 需要Frame: 160 59 | 2023-05--14 10:01:19 [FAILED]添加进程到阻塞队列: 1007 60 | 2023-05--14 10:01:20 [GC]回收进程 1003 ,大小: 70 61 | 2023-05--14 10:01:20 [FAILED]添加进程到阻塞队列: 1007 62 | 2023-05--14 10:01:21 [FAILED]添加进程到阻塞队列: 1007 63 | 2023-05--14 10:01:21 [ADD]添加进程: 1008 驻留时间: 5 需要Frame: 40 64 | 2023-05--14 10:01:21 [ALLOCATE]为进程1008分配, 大小: 40 起始frame: 120 本次分配耗时 : 22(ms) 65 | 2023-05--14 10:01:22 [FAILED]添加进程到阻塞队列: 1007 66 | 2023-05--14 10:01:23 [FAILED]添加进程到阻塞队列: 1007 67 | 2023-05--14 10:01:23 [ADD]添加进程: 1009 驻留时间: 1 需要Frame: 120 68 | 2023-05--14 10:01:23 [FAILED]添加进程到阻塞队列: 1009 69 | 2023-05--14 10:01:24 [GC]回收进程 1005 ,大小: 120 70 | 2023-05--14 10:01:24 [FAILED]添加进程到阻塞队列: 1007 71 | 2023-05--14 10:01:25 [ADD]添加进程: 1010 驻留时间: 3 需要Frame: 10 72 | 2023-05--14 10:01:25 [ALLOCATE]为进程1009分配, 大小: 120 起始frame: 0 本次分配耗时 : 32(ms) 73 | 2023-05--14 10:01:25 [ALLOCATE]为进程1010分配, 大小: 10 起始frame: 160 本次分配耗时 : 19(ms) 74 | 2023-05--14 10:01:26 [GC]回收进程 1008 ,大小: 40 75 | 2023-05--14 10:01:26 [GC]回收进程 1009 ,大小: 120 76 | 2023-05--14 10:01:26 [ALLOCATE]为进程1007分配, 大小: 160 起始frame: 0 本次分配耗时 : 63(ms) 77 | 2023-05--14 10:01:27 [GC]回收进程 1006 ,大小: 190 78 | 2023-05--14 10:01:27 [GC]回收进程 1007 ,大小: 160 79 | [测试结束] 分配总耗时: 464(ms) 80 | 2023-05--14 10:01:28 [GC]回收进程 1010 ,大小: 10 81 | */ 82 | } 83 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/algorithms/Priority.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms; 2 | 3 | import com.dhx.model.Process; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.LinkedList; 8 | import java.util.PriorityQueue; 9 | 10 | /** 11 | * @author dhx_ 12 | * @className Priority 优先级调度算法 : 这里的实现方法其实与SJF基本一致,区别在于PriorityQueue的排序规则由 消耗时间 变成了 优先级 13 | * @date : 2023/04/09/ 13:48 14 | **/ 15 | public class Priority { 16 | 17 | /** 18 | * 就绪队列最大容量 19 | */ 20 | int cap; 21 | 22 | /** 23 | * 累计的程序数量 24 | */ 25 | int totalProcessNum; 26 | 27 | /** 28 | * 已经执行的程序数量 29 | */ 30 | int completedNum; 31 | /** 32 | * 就绪队列 33 | */ 34 | Process running; 35 | /** 36 | * 就绪队列 : 每次从就绪队列中找到一个进程来执行 37 | */ 38 | PriorityQueue readyQueue; 39 | 40 | /** 41 | * 阻塞队列 42 | */ 43 | LinkedList blockQueue; 44 | 45 | /** 46 | * 添加进程 47 | * @param p 进程 48 | */ 49 | public void addProcess(Process p){ 50 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date())+ 51 | "\33[35;1m[ARRIVE]进程到达\33[0m, 进程ID :"+ p.getPID() +" 预计用时: "+p.getRunTime() +"(s)"); 52 | p.setStatus(Process.READY); 53 | p.setArriveTime(new Date()); // 设置到达时间 54 | // 如果当前的就绪队列已满, 那么把程序添加到阻塞队列(实际上的作用相当于挂载:suspend) 55 | if(readyQueue.size()>=cap){ 56 | p.setStatus(Process.BLOCK); 57 | blockQueue.add(p); 58 | return ; 59 | } 60 | readyQueue.add(p); 61 | totalProcessNum++; 62 | } 63 | 64 | /** 65 | * 执行进程 66 | */ 67 | private void executeProcess(){ 68 | while(running==null && (readyQueue.size()>0 || blockQueue.size()>0)){ 69 | if(readyQueue.size()<1){ 70 | fromBlock2Ready(); 71 | } 72 | // 从就绪队列中获取进程 73 | running=readyQueue.poll(); 74 | try{ 75 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date())+ 76 | "\33[92;1m[RUNNING]执行进程\33[0m 进程ID :"+ running.getPID()+ 77 | "\t耗时: "+running.getRunTime()+"(s)"+ 78 | " , 进程优先级为: "+running.getOrder()); 79 | Thread.sleep(running.getRunTime()*1000); 80 | }catch (InterruptedException e) { 81 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss") + "执行进程出现异常"); 82 | } 83 | running=null; 84 | } 85 | completedNum++; 86 | } 87 | 88 | /** 89 | * 把程序从阻塞队列移动到等待队列 90 | */ 91 | private void fromBlock2Ready(){ 92 | if(blockQueue.size() == 0){ 93 | return ; 94 | } 95 | while(blockQueue.size()>0 && readyQueue.size()0 || blockQueue.size()>0){ 115 | executeProcess(); 116 | } 117 | } 118 | } 119 | 120 | public Priority(int capacity){ 121 | this.cap =capacity; 122 | // 由于是高优先级率先执行 , 因此排序的规则为从大到小排序 123 | readyQueue=new PriorityQueue<>((o1,o2)-> (o2.getOrder() - o1.getOrder())); 124 | blockQueue=new LinkedList<>(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /页面置换算法/Java/com/dhx/algorithms/fifo/FIFO.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms.fifo; 2 | 3 | import com.dhx.model.DoubleLinkedList; 4 | import com.dhx.model.Element; 5 | 6 | import java.util.HashMap; 7 | import java.util.LinkedList; 8 | 9 | import static com.dhx.model.Constant.elements; 10 | 11 | /** 12 | * @author adorabled4 13 | * @className FIFO 选择最早进入物理内存的页面进行淘汰。 14 | * @date : 2023/05/06/ 09:57 15 | **/ 16 | public class FIFO { 17 | 18 | /** 19 | * key -> Element(key, val) 20 | */ 21 | private HashMap map; 22 | 23 | /** 24 | * 存储 Element(k1, v1) -> Element(k2, v2)... 25 | */ 26 | private LinkedList cache; 27 | 28 | /** 29 | * max capacity 30 | */ 31 | private int cap; 32 | 33 | /** 34 | * 统计缺页次数 35 | */ 36 | private int missingNum; 37 | 38 | /** 39 | * default capacity 40 | */ 41 | public static final int DEFAULT_CAPACITY = 10; 42 | 43 | 44 | /** 45 | * @param capacity FIFO容量 46 | */ 47 | public FIFO(int capacity) { 48 | if (capacity < 0) { 49 | this.cap = DEFAULT_CAPACITY; 50 | } else { 51 | this.cap = capacity; 52 | } 53 | map = new HashMap<>(); 54 | missingNum = 0; 55 | cache = new LinkedList<>(); 56 | } 57 | 58 | 59 | /** 60 | * 获取key对应的value 61 | * 62 | * @param key 63 | * @return 64 | */ 65 | public Element get(int key) { 66 | if (!map.containsKey(key)) { 67 | System.out.println("\u001B[35m\u001B[1m[MISS]\u001B[0m发生缺页中断,调入页: " + elements[key]); 68 | if (key > 10) { 69 | throw new RuntimeException("key范围超出测试数据范围!"); 70 | } 71 | put(elements[key]); 72 | missingNum++; 73 | return elements[key]; 74 | } 75 | System.out.println("\u001B[35m\u001B[1m[USE]\u001B[0m从cache使用页,Data: " + map.get(key)); 76 | return map.get(key); 77 | } 78 | 79 | /** 80 | * 获取缺页次数 81 | * 82 | * @return 83 | */ 84 | public int getMissingNum() { 85 | return missingNum; 86 | } 87 | 88 | /** 89 | * 向FIFO中添加数据 90 | * 91 | * @param key 92 | * @param val 93 | */ 94 | public void put(int key, int val) { 95 | Element element = new Element(key, val); 96 | System.out.println("\u001B[32m\u001B[1m[ADD]\u001B[0m添加页到cache,Data: " + element); 97 | // 1. 页面已经在内存中 98 | // 2. 没有在内存中 99 | if (!map.containsKey(key)) { 100 | // 需要进行置换 101 | if (cap == cache.size()) { 102 | // 注意需要从map中也删除element 103 | Element poll = cache.poll(); 104 | map.remove(poll.key); 105 | } 106 | cache.addLast(element); 107 | map.put(element.key, element); 108 | } 109 | } 110 | 111 | /** 112 | * 向队列中添加数据 113 | */ 114 | public void put(Element element) { 115 | System.out.println("\u001B[32m\u001B[1m[ADD]\u001B[0m添加页到cache,Data: " + element); 116 | // 1. 页面已经在内存中 117 | // 2. 没有在内存中 118 | if (!map.containsKey(element.key)) { 119 | while (cache.size()>=cap) { 120 | Element poll = cache.poll(); 121 | map.remove(poll.key); 122 | } 123 | cache.addLast(element); 124 | map.put(element.key, element); 125 | } 126 | } 127 | 128 | @Override 129 | public String toString() { 130 | StringBuffer stringBuffer = new StringBuffer(); 131 | stringBuffer.append("Pages:{ "); 132 | cache.forEach(item -> { 133 | stringBuffer.append(item + "--> "); 134 | }); 135 | return stringBuffer.substring(0, stringBuffer.length() - 4) + " }".toString(); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /进程调度算法/Python/PS.py: -------------------------------------------------------------------------------- 1 | # 丁士钦 2023.5.19 PS调度算法 2 | 3 | 4 | from typing import List 5 | 6 | 7 | class PCB: 8 | def __init__(self, name: str, arrive_time: int, service_time: int, weight: int): 9 | self.name = name 10 | self.arrive_time = arrive_time 11 | self.service_time = service_time 12 | self.weight = weight 13 | self.r_service_time = service_time 14 | self.state = 'W' # W: waiting, R: running, F: finished 15 | self.id = 0 16 | self.finish_time = 0 17 | self.run_time = 0 18 | self.avg_time = 0 19 | 20 | def is_waiting(self, current_time: int) -> bool: 21 | return self.r_service_time > 0 and self.arrive_time <= current_time 22 | 23 | 24 | class PS: 25 | def __init__(self): 26 | self.n = 0 27 | self.ps_array: List[PCB] = [] 28 | self.current_time = 0 29 | self.wait_list: List[PCB] = [] 30 | 31 | def init(self) -> None: 32 | print("请输入进程数:") 33 | self.n = int(input().strip()) 34 | for i in range(self.n): 35 | print(f"请依次输入第{i + 1}个进程的姓名,进程到达时间,进程服务时间,进程的优先级:") 36 | name, arrive_time, service_time, weight = input().split() 37 | pcb = PCB(name, int(arrive_time), int(service_time), int(weight)) 38 | pcb.id = i 39 | self.ps_array.append(pcb) 40 | self.ps_array.sort(key=lambda x: x.arrive_time) 41 | 42 | # 显示每个时刻的进程情况 43 | def show(self) -> None: 44 | print("当前时刻\t进程名\t剩余服务时间\t优先级\t进程状态") 45 | for pcb in self.ps_array: 46 | print(f"{self.current_time}--{self.current_time + 1}\t{pcb.name}\t{pcb.r_service_time}\t\t{pcb.weight}\t{pcb.state}") 47 | print("--------------------------------------------------------------") 48 | 49 | # 打印最终结果,周转时间和带权周转时间 50 | def print_result(self) -> None: 51 | # 计算周转时间 52 | for pcb in self.ps_array: 53 | pcb.run_time = pcb.finish_time - pcb.arrive_time 54 | pcb.avg_time = pcb.run_time / pcb.service_time 55 | 56 | print("进程名\t结束时间\t周转时间\t带权周转时间") 57 | for pcb in self.ps_array: 58 | print(f"{pcb.name}\t{pcb.finish_time}\t\t{pcb.run_time}\t\t{pcb.avg_time}") 59 | 60 | # 运行 61 | def run(self) -> None: 62 | self.current_time = 0 # 记录当前时刻 63 | # 已完成的进程数,初始化为0 64 | finished_count = self.n 65 | while finished_count != 0: 66 | # 判断当前时刻到达的进程,并将它添加到容器wait_list中 67 | self.wait_list = [pcb for pcb in self.ps_array if pcb.is_waiting(self.current_time)] 68 | 69 | tmp = PCB('', 0, 0, -100) 70 | index = 0 71 | # 执行当前等待进程中优先级最高的那一个 72 | for i, pcb in enumerate(self.wait_list): 73 | if pcb.weight > tmp.weight: 74 | tmp = pcb 75 | index = i 76 | 77 | # 更新所有进程的状态 78 | for i, pcb in enumerate(self.ps_array): 79 | if pcb.is_waiting(self.current_time): 80 | self.ps_array[i].state = 'W' 81 | if tmp.id == pcb.id: 82 | self.ps_array[i].state = 'R' 83 | self.ps_array[i].weight -= 1 84 | self.ps_array[i].r_service_time -= 1 85 | self.show() 86 | if self.ps_array[i].r_service_time == 0: 87 | self.ps_array[i].state = 'F' 88 | finished_count -= 1 89 | self.ps_array[i].finish_time = self.current_time + 1 90 | 91 | # 更新当前时刻 92 | self.current_time += 1 93 | 94 | 95 | if __name__ == "__main__": 96 | # 创建PS对象 97 | ps = PS() 98 | 99 | # 初始化进程 100 | ps.init() 101 | 102 | # 运行进程调度 103 | ps.run() 104 | 105 | # 打印最终结果 106 | ps.print_result() 107 | -------------------------------------------------------------------------------- /磁盘调度算法/C++/algorithms/SCAN.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 扫描(SCAN)调度算法 3 | // Created by 侯金科 on 2023/5/12. 4 | // 5 | 6 | /* 7 | * SCAN算法是最佳寻道时间优先算法,也叫电梯调度算法, 8 | * 它根据磁头的移动方向,先处理所有同向的请求,然后再处理相反方向的请求。 9 | * 它的优点是避免了饥饿现象,提高了磁盘访问效率。它的缺点是当磁头移到磁盘一端并反转方向时, 10 | * 紧靠磁头前方的请求相对较少,而磁盘另一端的请求密度却是最多。 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | class SCAN { 19 | private: 20 | int n; // 磁盘请求数目 21 | int* request; // 磁盘请求序列 22 | int head; // 磁头初始位置 23 | int direction; // 磁头移动方向,1为增加方向,-1为减少方向 24 | public: 25 | SCAN(int n, int* request, int head) { 26 | this->n = n; 27 | this->request = request; 28 | this->head = head; 29 | sort(request, request + n); // 对请求序列进行升序排序 30 | //判断走向,可以用二分 31 | for(int i=0;idirection = 1; 35 | else this->direction = -1; 36 | break; 37 | } 38 | } 39 | } 40 | 41 | void schedule() { 42 | int distance = 0; // 磁头移动距离 43 | int seekTime = 0; // 磁头寻道总距离 44 | cout << "SCAN算法调度过程如下:" << endl; 45 | if (direction == 1) { // 如果磁头向增加方向移动 46 | for (int i = 0; i < n; i++) { 47 | if (request[i] >= head) { // 如果请求在当前磁头位置或之后 48 | distance = abs(request[i] - head); // 计算磁头移动距离 49 | seekTime += distance; // 累加磁头寻道距离 50 | cout << "从" << head << "号磁道移动到" << request[i] << "号磁道,移动距离为" << distance << endl; 51 | head = request[i]; // 更新磁头位置 52 | } 53 | } 54 | for (int i = n - 1; i >= 0; i--) { 55 | if (request[i] < head) { // 如果请求在当前磁头位置之前 56 | distance = abs(request[i] - head); // 计算磁头移动距离 57 | seekTime += distance; // 累加磁头寻道距离 58 | cout << "从" << head << "号磁道移动到" << request[i] << "号磁道,移动距离为" << distance << endl; 59 | head = request[i]; // 更新磁头位置 60 | } 61 | } 62 | } else if (direction == -1) { // 如果磁头向减少方向移动 63 | for (int i = n - 1; i >= 0; i--) { 64 | if (request[i] <= head) { // 如果请求在当前磁头位置或之前 65 | distance = abs(request[i] - head); // 计算磁头移动距离 66 | seekTime += distance; // 累加磁头寻道距离 67 | cout << "从" << head << "号磁道移动到" << request[i] << "号磁道,移动距离为" << distance << endl; 68 | head = request[i]; // 更新磁头位置 69 | } 70 | } 71 | for (int i = 0; i < n; i++) { 72 | if (request[i] > head) { // 如果请求在当前磁头位置之后 73 | distance = abs(request[i] - head); // 计算磁头移动距离 74 | seekTime += distance; // 累加磁头寻道距离 75 | cout << "从" << head << "号磁道移动到" << request[i] << "号磁道,移动距离为" << distance << endl; 76 | head = request[i]; // 更新磁头位置 77 | } 78 | } 79 | } 80 | cout << "SCAN算法调度结束" << endl; 81 | cout << "总移动距离为:" << seekTime << endl; 82 | cout << "平均寻道长度为:" << (double)seekTime / n << endl; 83 | } 84 | }; 85 | 86 | int main() { 87 | //解决CLion控制台乱码问题 88 | system("chcp 65001"); 89 | cout << "请输入磁盘请求数目:" << endl; 90 | int n; // 磁盘请求数目 91 | cin >> n; 92 | int* request = new int[n]; // 磁盘请求序列 93 | cout << "请输入磁盘请求序列:" << endl; 94 | for (int i = 0; i < n; i++) { 95 | cin >> request[i]; // 输入磁盘请求序列 96 | } 97 | cout << "请输入磁头初始位置:" << endl; 98 | int head; // 磁头初始位置 99 | cin >> head; 100 | 101 | SCAN scan(n, request, head); // 创建SCAN对象 102 | scan.schedule(); // 调用schedule方法进行调度 103 | 104 | delete[] request; // 释放动态数组内存 105 | return 0; 106 | } 107 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/model/Process.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.model; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author dhx_ 7 | * @className 进程 8 | * @date : 2023-5-13 15:13:16 9 | **/ 10 | public class Process { 11 | 12 | /** 13 | * 进程ID 14 | */ 15 | int PID; 16 | 17 | /** 18 | * 进程状态 19 | */ 20 | int status; 21 | 22 | /** 23 | * 进程优先级 24 | */ 25 | int order; 26 | 27 | /** 28 | * 执行时间 29 | */ 30 | long runTime; 31 | 32 | /** 33 | * 到达时间(时刻) 34 | */ 35 | Date arriveTime; 36 | 37 | /** 38 | * 结束时间(时刻) 39 | */ 40 | Date finishTime; 41 | 42 | /** 43 | * 周转时间 : 周转时间=结束时间-到达时间 44 | */ 45 | long cycleTime; 46 | 47 | /** 48 | * 平均周转时间 : 平均周转时间=周转时间/运行时间 49 | */ 50 | long aveCycleTime; 51 | 52 | /** 53 | * 需要的 帧 的数量 54 | */ 55 | int frameSize; 56 | 57 | /** 58 | * HRRN 算法的优先权 59 | */ 60 | double preemption; 61 | 62 | long timeConsume; 63 | 64 | public long getTimeConsume() { 65 | return timeConsume; 66 | } 67 | 68 | public void setTimeConsume(long timeConsume) { 69 | this.timeConsume = timeConsume; 70 | } 71 | 72 | public double getPreemption() { 73 | return preemption; 74 | } 75 | 76 | public void setPreemption(double preemption) { 77 | this.preemption = preemption; 78 | } 79 | 80 | public Process(int PID , int runTime,int frameSize){ 81 | this.PID=PID; 82 | this.runTime=runTime; // 设置进程需要的执行时间 83 | this.frameSize=frameSize; 84 | order=DEFAULT_ORDER; 85 | status=READY; // 此处模拟进程分配 , 默认初始进程状态为READY 86 | this.arriveTime=new Date(); 87 | } 88 | 89 | /** 90 | * 进程就绪 91 | */ 92 | public static final int READY=1; 93 | 94 | /** 95 | * 进程阻塞 96 | */ 97 | public static final int BLOCK=2; 98 | 99 | /** 100 | * 执行 101 | */ 102 | public static final int RUNNING=3; 103 | 104 | /** 105 | * 默认进程优先级 106 | */ 107 | public static final int DEFAULT_ORDER=0; 108 | 109 | 110 | public int getPID() { 111 | return PID; 112 | } 113 | 114 | 115 | public int getStatus() { 116 | return status; 117 | } 118 | 119 | public void setStatus(int status) { 120 | this.status = status; 121 | } 122 | 123 | public int getOrder() { 124 | return order; 125 | } 126 | 127 | public void setOrder(int order) { 128 | this.order = order; 129 | } 130 | 131 | public long getRunTime() { 132 | return runTime; 133 | } 134 | 135 | public void setRunTime(long runTime) { 136 | this.runTime = runTime; 137 | } 138 | 139 | public Date getArriveTime() { 140 | return arriveTime; 141 | } 142 | 143 | public void setArriveTime(Date arriveTime) { 144 | this.arriveTime = arriveTime; 145 | } 146 | 147 | public Date getFinishTime() { 148 | return finishTime; 149 | } 150 | 151 | public void setFinishTime(Date finishTime) { 152 | this.finishTime = finishTime; 153 | } 154 | 155 | public long getCycleTime() { 156 | return cycleTime; 157 | } 158 | 159 | public void setCycleTime(long cycleTime) { 160 | this.cycleTime = cycleTime; 161 | } 162 | 163 | public long getAveCycleTime() { 164 | return aveCycleTime; 165 | } 166 | 167 | public void setAveCycleTime(long aveCycleTime) { 168 | this.aveCycleTime = aveCycleTime; 169 | } 170 | 171 | public int getFrameSize() { 172 | return frameSize; 173 | } 174 | 175 | public void setFrameSize(int frameSize) { 176 | this.frameSize = frameSize; 177 | } 178 | 179 | public void setPID(int PID) { 180 | this.PID = PID; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/sample/NFExample.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.sample; 2 | 3 | import com.os.dynamicmatching.algorithms.FF; 4 | import com.os.dynamicmatching.algorithms.NF; 5 | import com.os.dynamicmatching.model.Process; 6 | import com.os.dynamicmatching.util.RandomTestUtil; 7 | import com.os.dynamicmatching.util.TimeUtil; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * @author adorabled4 13 | * @className NFExample 14 | * @date : 2023-5-13 19:13:31 15 | **/ 16 | public class NFExample { 17 | 18 | 19 | public static void main(String[] args){ 20 | testNF(500, 10); 21 | } 22 | 23 | /** 24 | * 测试 动态分区匹配算法 仅仅测试当前算法的执行方式以及内容 25 | * @param cap frame容量 26 | * @param processSize 进程的个数 27 | */ 28 | static void testNF(int cap,int processSize){ 29 | List timeCounts = RandomTestUtil.testDynamicMatching(cap, processSize, NF.class); 30 | long timeCount =0; 31 | for (Long count : timeCounts) { 32 | timeCount+=count; 33 | } 34 | System.out.println("\u001B[31m\u001B[1m[测试结束]\u001B[0m 总耗时: "+timeCount+ "(ms)"); 35 | } 36 | /* 37 | 下面是一组测试示例 38 | 2023-05--14 10:41:20 [ADD]添加进程: 1001 驻留时间: 7(s) 需要Frame: 160 39 | 2023-05--14 10:41:20 [ALLOCATE]为进程1001分配, 大小: 160 起始frame: 0 本次分配耗时 : 93(ms) 40 | 2023-05--14 10:41:22 [ADD]添加进程: 1002 驻留时间: 9(s) 需要Frame: 140 41 | 2023-05--14 10:41:22 [ALLOCATE]为进程1002分配, 大小: 140 起始frame: 160 本次分配耗时 : 123(ms) 42 | 2023-05--14 10:41:24 [ADD]添加进程: 1003 驻留时间: 9(s) 需要Frame: 80 43 | 2023-05--14 10:41:24 [ALLOCATE]为进程1003分配, 大小: 80 起始frame: 300 本次分配耗时 : 44(ms) 44 | 2023-05--14 10:41:26 [ADD]添加进程: 1004 驻留时间: 8(s) 需要Frame: 180 45 | 2023-05--14 10:41:26 [FAILED]添加进程到阻塞队列: 1004 46 | 2023-05--14 10:41:27 [FAILED]添加进程到阻塞队列: 1004 47 | 2023-05--14 10:41:27 [GC]回收进程 1001 ,大小: 160 48 | 2023-05--14 10:41:28 [FAILED]添加进程到阻塞队列: 1004 49 | 2023-05--14 10:41:28 [ADD]添加进程: 1005 驻留时间: 9(s) 需要Frame: 50 50 | 2023-05--14 10:41:28 [ALLOCATE]为进程1005分配, 大小: 50 起始frame: 0 本次分配耗时 : 12(ms) 51 | 2023-05--14 10:41:29 [FAILED]添加进程到阻塞队列: 1004 52 | 2023-05--14 10:41:30 [FAILED]添加进程到阻塞队列: 1004 53 | 2023-05--14 10:41:30 [ADD]添加进程: 1006 驻留时间: 10(s) 需要Frame: 100 54 | 2023-05--14 10:41:30 [ALLOCATE]为进程1006分配, 大小: 100 起始frame: 50 本次分配耗时 : 24(ms) 55 | 2023-05--14 10:41:31 [GC]回收进程 1002 ,大小: 140 56 | 2023-05--14 10:41:31 [FAILED]添加进程到阻塞队列: 1004 57 | 2023-05--14 10:41:32 [ADD]添加进程: 1007 驻留时间: 1(s) 需要Frame: 200 58 | 2023-05--14 10:41:32 [FAILED]添加进程到阻塞队列: 1004 59 | 2023-05--14 10:41:32 [FAILED]添加进程到阻塞队列: 1007 60 | 2023-05--14 10:41:33 [GC]回收进程 1003 ,大小: 80 61 | 2023-05--14 10:41:33 [ALLOCATE]为进程1004分配, 大小: 180 起始frame: 150 本次分配耗时 : 62(ms) 62 | 2023-05--14 10:41:34 [FAILED]添加进程到阻塞队列: 1007 63 | 2023-05--14 10:41:34 [ADD]添加进程: 1008 驻留时间: 4(s) 需要Frame: 80 64 | 2023-05--14 10:41:34 [ALLOCATE]为进程1008分配, 大小: 80 起始frame: 330 本次分配耗时 : 47(ms) 65 | 2023-05--14 10:41:35 [FAILED]添加进程到阻塞队列: 1007 66 | 2023-05--14 10:41:36 [FAILED]添加进程到阻塞队列: 1007 67 | 2023-05--14 10:41:36 [ADD]添加进程: 1009 驻留时间: 3(s) 需要Frame: 90 68 | 2023-05--14 10:41:36 [FAILED]添加进程到阻塞队列: 1009 69 | 2023-05--14 10:41:37 [GC]回收进程 1005 ,大小: 50 70 | 2023-05--14 10:41:37 [FAILED]添加进程到阻塞队列: 1007 71 | 2023-05--14 10:41:38 [GC]回收进程 1008 ,大小: 80 72 | 2023-05--14 10:41:38 [ALLOCATE]为进程1009分配, 大小: 90 起始frame: 330 本次分配耗时 : 89(ms) 73 | 2023-05--14 10:41:38 [ADD]添加进程: 1010 驻留时间: 1(s) 需要Frame: 40 74 | 2023-05--14 10:41:38 [ALLOCATE]为进程1010分配, 大小: 40 起始frame: 0 本次分配耗时 : 9(ms) 75 | 2023-05--14 10:41:39 [FAILED]添加进程到阻塞队列: 1007 76 | 2023-05--14 10:41:39 [GC]回收进程 1010 ,大小: 40 77 | 2023-05--14 10:41:40 [GC]回收进程 1006 ,大小: 100 78 | 2023-05--14 10:41:40 [FAILED]添加进程到阻塞队列: 1007 79 | 2023-05--14 10:41:41 [GC]回收进程 1004 ,大小: 180 80 | 2023-05--14 10:41:41 [GC]回收进程 1009 ,大小: 90 81 | 2023-05--14 10:41:41 [ALLOCATE]为进程1007分配, 大小: 200 起始frame: 0 本次分配耗时 : 159(ms) 82 | [测试结束] 总耗时: 352(ms) 83 | 2023-05--14 10:41:42 [GC]回收进程 1007 ,大小: 200 84 | */ 85 | } 86 | -------------------------------------------------------------------------------- /动态分区匹配算法/Java/com/os/dynamicmatching/algorithms/WF.java: -------------------------------------------------------------------------------- 1 | package com.os.dynamicmatching.algorithms; 2 | 3 | import com.os.dynamicmatching.model.DMConstant; 4 | import com.os.dynamicmatching.model.Frame; 5 | import com.os.dynamicmatching.model.Process; 6 | import com.os.dynamicmatching.util.AlgorithmUtil; 7 | import com.os.dynamicmatching.util.TimeUtil; 8 | 9 | import java.util.ArrayList; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author adorabled4 16 | * @className WF : 从所有空闲分区中找到大小最接近请求大小的分区,将其分配给程序使用。 17 | * @date : 2023-5-16 13:13:00 18 | **/ 19 | public class WF extends Thread implements Runnable { 20 | 21 | /** 22 | * 帧 23 | */ 24 | List mem; 25 | /** 26 | * 帧容量 27 | */ 28 | int cap; 29 | 30 | /** 31 | * 阻塞进程 32 | */ 33 | LinkedList blockingQueue; 34 | 35 | /** 36 | * 执行标志 : 一定要加上volatile , 否则不会停止 ! 37 | */ 38 | volatile boolean runFlag = true; 39 | 40 | public void setRunFlag(boolean flag) { 41 | runFlag = flag; 42 | } 43 | 44 | public WF() { 45 | mem = new ArrayList<>(DMConstant.DEFAULT_FRAME_SIZE);// 设置内存的大小 46 | blockingQueue = new LinkedList<>(); 47 | for (int i = 0; i < DMConstant.DEFAULT_FRAME_SIZE; i++) { 48 | mem.add(new Frame(i, DMConstant.FREE)); 49 | } 50 | } 51 | 52 | public WF(int cap) { 53 | mem = new ArrayList<>(cap);// 设置内存的大小 54 | this.cap = cap; 55 | blockingQueue = new LinkedList<>(); 56 | for (int i = 0; i < cap; i++) { 57 | mem.add(new Frame(i, DMConstant.FREE)); 58 | } 59 | } 60 | 61 | /** 62 | * 分配内存 63 | * 64 | * @param process 65 | */ 66 | public synchronized long allocate(Process process) { 67 | // 从内存的起始点开始遍历,找到第一个空闲的分区 68 | long startTime = System.nanoTime(); 69 | List> partitions = AlgorithmUtil.searchPartition(this.mem); 70 | if (partitions.size() == 0) { 71 | // 当前没有空闲分区 72 | addBlockingQueue(process); 73 | return -1; 74 | } 75 | System.out.println("\u001B[34m\u001B[1m" + TimeUtil.getCurrentTime() + "当前空闲分区情况:\u001B[0m"); 76 | // Print each partition in the list 77 | for (int i = 0; i < partitions.size(); i++) { 78 | System.out.print("\t\u001B[34m\u001B[1m[Partition]\u001B[0m #: " + (i + 1) + ":"); 79 | Map partition = partitions.get(i); 80 | for (Map.Entry entry : partition.entrySet()) { 81 | int size = entry.getKey(); 82 | int[] range = entry.getValue(); 83 | System.out.println("Size: " + size + ", Range: [" + range[0] + ", " + range[1] + "]"); 84 | } 85 | } 86 | // 分配最大的的分区给进程 87 | if (partitions.get(0).keySet().iterator().next() >= process.getFrameSize()) { 88 | //刚好一块可以满足 (例如最出初始的情况) 89 | int startFrame = partitions.get(0).values().iterator().next()[0]; 90 | AlgorithmUtil.allocateMem(startFrame, mem, process, startTime); 91 | return process.getTimeConsume(); 92 | }else{ 93 | addBlockingQueue(process); 94 | return -1; 95 | } 96 | } 97 | 98 | /** 99 | * 添加进程到阻塞队列 ,(无可用内存分配) 100 | * 101 | * @param process 102 | */ 103 | private void addBlockingQueue(Process process) { 104 | process.setStatus(Process.BLOCK); 105 | blockingQueue.add(process); 106 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[32m\u001B[1m[FAILED]\u001B[0m添加进程到阻塞队列: " + process.getPID()); 107 | } 108 | 109 | 110 | @Override 111 | public void run() { 112 | while (runFlag) { 113 | while (blockingQueue.size() > 0) { 114 | // 先睡眠 , 然后再进行添加, 防止某些时刻帧不足 , 占用极高的进程持续的访问锁, 浪费资源 115 | try { 116 | Thread.sleep(1000); 117 | } catch (InterruptedException e) { 118 | throw new RuntimeException(e); 119 | } 120 | Process poll = blockingQueue.poll(); 121 | allocate(poll); 122 | } 123 | } 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /进程调度算法/C++/algorithms/SRTF.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/14. 3 | // 4 | #include "../model/PCB.h" 5 | 6 | // 定义一个比较函数,按照到达时间升序排序 7 | bool cmpArrive(const PCB& p1, const PCB& p2) { 8 | return p1.arriveTime < p2.arriveTime; 9 | } 10 | 11 | void init() 12 | { 13 | cout<<"请输入进程数"; 14 | cin>>SRTFobject.n; 15 | for(int i=0;i>tmp.Name>>tmp.arriveTime>>tmp.serviceTime; 20 | //初始剩余服务时间等于服务时间 21 | tmp.rserviceTime=tmp.serviceTime; 22 | SRTFobject.SRTFarray.push_back(tmp); 23 | } 24 | 25 | sort(SRTFobject.SRTFarray.begin(), SRTFobject.SRTFarray.end(), cmpArrive); 26 | } 27 | // 定义一个函数,实现SrserviceTimeF调度算法 28 | void Run() { 29 | // 定义一个变量表示当前时间 30 | int CurrentTime = 0; 31 | // 定义一个变量表示已完成的进程数 32 | int hFinish = 0; 33 | // 定义一个变量表示当前执行的进程编号,初始为-1表示没有进程执行 34 | int currentPCB = -1; 35 | // 循环直到所有进程都完成 36 | while (hFinish < SRTFobject.SRTFarray.size()) { 37 | // 遍历所有进程,找出当前时间可以执行的剩余时间最短的进程 38 | int shortestPCB = -1; 39 | int shortestTime = INT_MAX; 40 | for (int i = 0; i < SRTFobject.SRTFarray.size(); i++) { 41 | if (SRTFobject.SRTFarray[i].arriveTime <= CurrentTime && SRTFobject.SRTFarray[i].rserviceTime > 0) { 42 | SRTFobject.SRTFarray[i].State=W; 43 | if (SRTFobject.SRTFarray[i].rserviceTime < shortestTime ) { 44 | shortestPCB = i; 45 | shortestTime = SRTFobject.SRTFarray[i].rserviceTime; 46 | } 47 | } 48 | } 49 | 50 | // 如果找到了可执行的进程,更新当前执行的进程编号 51 | if (shortestPCB != -1) { 52 | if( SRTFobject.SRTFarray[currentPCB].rserviceTime==0){ 53 | SRTFobject.SRTFarray[currentPCB].State=F; 54 | } 55 | else SRTFobject.SRTFarray[currentPCB].State=W; 56 | currentPCB = shortestPCB; 57 | SRTFobject.SRTFarray[currentPCB].State=R; 58 | } 59 | // 如果没有找到可执行的进程,说明当前没有进程到达,将当前时间加一后继续循环 60 | if (currentPCB == -1) { 61 | SRTFobject.SRTFarray[currentPCB].State=R; 62 | CurrentTime++; 63 | continue; 64 | } 65 | // 如果当前执行的进程是第一次执行,记录其开始时间 66 | if (SRTFobject.SRTFarray[currentPCB].st == -1) { 67 | SRTFobject.SRTFarray[currentPCB].st = CurrentTime; 68 | SRTFobject.SRTFarray[currentPCB].State=R; 69 | } 70 | 71 | // 将当前执行的进程的剩余时间减一,表示执行了一个单位时间 72 | SRTFobject.SRTFarray[currentPCB].rserviceTime--; 73 | 74 | // 如果当前执行的进程的剩余时间为零,表示该进程已完成,记录其完成时间、等待时间和周转时间,并将已完成的进程数加一 75 | if (SRTFobject.SRTFarray[currentPCB].rserviceTime == 0) { 76 | SRTFobject.SRTFarray[currentPCB].finishTime = CurrentTime + 1; 77 | SRTFobject.SRTFarray[currentPCB].State=F; 78 | //计算周转时间和带权周转时间 79 | SRTFobject.SRTFarray[currentPCB].RunTime = SRTFobject.SRTFarray[currentPCB].finishTime - SRTFobject.SRTFarray[currentPCB].arriveTime; 80 | SRTFobject.SRTFarray[currentPCB].avgTime = SRTFobject.SRTFarray[currentPCB].RunTime / SRTFobject.SRTFarray[currentPCB].serviceTime; 81 | hFinish++; 82 | } 83 | // 将当前时间加一,表示进入下一个单位时间 84 | cout<<"当前时刻"<<" "<<"进程名"<<" "<<"进程剩余服务时间"<<" "<<"进程状态"< algorithm, int size, int min, int max, int head) { 60 | try { 61 | // 获取 构造器 62 | Constructor constructor = algorithm.getConstructor(int.class, int[].class, int.class); 63 | int[] request = TestUtil.generateRequestArray(size, min, max); // 磁盘请求序列 64 | System.out.println("测试开始" + 65 | "\t本次测试算法为: " + algorithm.getSimpleName() + 66 | "\t本次调度数组大小: " + size + 67 | "\t磁头初始位置: " + head + 68 | "\t磁盘请求序列为: "); 69 | printArray(request); 70 | // 获取 对象实例 71 | Object instance = constructor.newInstance(size, request, head); 72 | Method schedule = algorithm.getMethod("schedule"); 73 | // 执行调度 74 | schedule.invoke(instance); 75 | } catch (Exception e) { 76 | throw new RuntimeException(e); 77 | } 78 | } 79 | 80 | 81 | /** 82 | * 用于对比测试 83 | * @param classes 84 | * @param size 85 | * @param min 86 | * @param max 87 | * @param head 88 | */ 89 | public static void algorithmTest(Class[] classes, int size, int min, int max, int head) { 90 | Map map = new HashMap<>(); // name : testResult 91 | int[] request = TestUtil.generateRequestArray(size, min, max); // 磁盘请求序列 92 | for (Class algorithm : classes) { 93 | try { 94 | // 获取 构造器 95 | Constructor constructor = algorithm.getConstructor(int.class, int[].class, int.class); 96 | System.out.println("\n测试开始" + 97 | "\t本次测试算法为: \033[1m" + algorithm.getSimpleName() + 98 | "\033[0m\t本次调度数组大小: " + size + 99 | "\t磁头初始位置: " + head + 100 | "\t磁盘请求序列为: "); 101 | // 获取 对象实例 102 | Object instance = constructor.newInstance(size, request, head); 103 | Method schedule = algorithm.getMethod("schedule"); 104 | // 执行调度 105 | Object value = schedule.invoke(instance); 106 | Integer seekTime = (Integer) value; 107 | StringBuilder sb = new StringBuilder(""); 108 | sb.append("总移动距离为:").append(seekTime).append(",平均寻道长度为:").append((double) seekTime / size); 109 | // 存储数据 110 | map.put(algorithm.getSimpleName(), sb.toString()); 111 | } catch (Exception e) { 112 | throw new RuntimeException(e); 113 | } 114 | } 115 | // 打印结果 116 | System.out.println("\u001B[34m\u001B[1m[对比测试完毕]\u001B[0m"); 117 | System.out.printf("%-20s%-25s\n", "\033[1m算法名称\033[0m", "\t\t\033[1m平均寻道长度\033[0m"); 118 | map.forEach((key, value) -> System.out.printf("%-20s%-25s\n", key, value)); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /进程调度算法/C++/algorithms/PS.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by 刘晋昂 on 2023/5/9. 3 | // 4 | #include "../model/PCB.h" 5 | 6 | //判断进程到达的先后顺序 7 | bool cmpArrive(PCB &a, PCB &b) 8 | { 9 | return a.arriveTime < b.arriveTime; 10 | } 11 | //按到达先后顺序在数组中排序 12 | void init() 13 | { 14 | cout<<"请输入进程数"; 15 | cin>>PSobject.n; 16 | for(int i=0;i>PSobject.PSarray[i].Name>>PSobject.PSarray[i].arriveTime>>PSobject.PSarray[i].serviceTime>>PSobject.PSarray[i].weight; 19 | PSobject.PSarray[i].id=i; 20 | //初始剩余服务时间等于服务时间 21 | PSobject.PSarray[i].rserviceTime=PSobject.PSarray[i].serviceTime; 22 | } 23 | sort(PSobject.PSarray,PSobject.PSarray+PSobject.n,cmpArrive); 24 | for(int i=0;i0&&PSobject.PSarray[i].arriveTime<=PSobject.CurrentTime) { 62 | PSobject.WaitList.push_back(PSobject.PSarray[i]); 63 | } 64 | } 65 | 66 | // for(int i=0;itmp.weight){ 78 | tmp=PSobject.WaitList[i]; 79 | index=i; 80 | } 81 | } 82 | //优先级最高的那个进程优先级-1,剩余服务时间-1,进程状态变为running, 83 | for(int i=0;i mem; 24 | /** 25 | * 帧容量 26 | */ 27 | int cap; 28 | 29 | /** 30 | * 阻塞进程 31 | */ 32 | LinkedList blockingQueue; 33 | 34 | /** 35 | * 执行标志 : 一定要加上volatile , 否则不会停止 ! 36 | */ 37 | volatile boolean runFlag = true; 38 | 39 | public void setRunFlag(boolean flag) { 40 | runFlag = flag; 41 | } 42 | 43 | public FF() { 44 | mem = new ArrayList<>(DMConstant.DEFAULT_FRAME_SIZE);// 设置内存的大小 45 | blockingQueue = new LinkedList<>(); 46 | for (int i = 0; i < DMConstant.DEFAULT_FRAME_SIZE; i++) { 47 | mem.add(new Frame(i, DMConstant.FREE)); 48 | } 49 | } 50 | 51 | public FF(int cap) { 52 | mem = new ArrayList<>(cap);// 设置内存的大小 53 | this.cap = cap; 54 | blockingQueue = new LinkedList<>(); 55 | for (int i = 0; i < cap; i++) { 56 | mem.add(new Frame(i, DMConstant.FREE)); 57 | } 58 | } 59 | 60 | /** 61 | * 分配内存 62 | * 63 | * @param process 64 | */ 65 | public synchronized long allocate(Process process) { 66 | // 从内存的起始点开始遍历,找到第一个空闲的分区 67 | long start = System.nanoTime(); 68 | for (int i = 0; i < mem.size(); i++) { 69 | if (mem.get(i).getStatus() == DMConstant.FREE) { 70 | // 超出限制 71 | if (i + process.getFrameSize() >= cap) { 72 | process.setStatus(Process.BLOCK); 73 | blockingQueue.add(process); 74 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[32m\u001B[1m[FAILED]\u001B[0m添加进程到阻塞队列: " + process.getPID()); 75 | return -1; 76 | } else { 77 | if (mem.get(i + process.getFrameSize() - 1).getStatus() == DMConstant.FREE) { 78 | boolean isAllFree = true; 79 | // 查看是否有连续空闲的分区 80 | for (int j = i + 1; j < i + process.getFrameSize(); j++) { 81 | if (mem.get(j).getStatus() == DMConstant.USED) { 82 | isAllFree = false; 83 | break; 84 | } 85 | } 86 | // 进行分配 87 | if (isAllFree) { 88 | for (int j = i + 1; j < i + process.getFrameSize(); j++) { 89 | mem.get(j).setStatus(DMConstant.USED); 90 | } 91 | process.setStatus(Process.READY); 92 | // 分配成功, 打印日志 93 | long timeConsume = (System.nanoTime() - start) / 1000; 94 | process.setTimeConsume(timeConsume); 95 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[33m\u001B[1m[ALLOCATE]\u001B[0m为进程" + process.getPID() + "分配, 大小: " + process.getFrameSize() + " 起始frame: " + i + " 本次分配耗时 : " + process.getTimeConsume() + "(ms)"); 96 | int finalI = i; 97 | // 执行进程之后,进行回收 98 | RandomTestUtil.runAndMemCollect(process, finalI,mem); 99 | return process.getTimeConsume(); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | process.setStatus(Process.BLOCK); 106 | blockingQueue.add(process); 107 | System.out.println(TimeUtil.getCurrentTime() + "\u001B[32m\u001B[1m[FAILED]\u001B[0m添加进程到阻塞队列: " + process.getPID()); 108 | return -1; 109 | } 110 | 111 | 112 | 113 | @Override 114 | public void run() { 115 | while (runFlag) { 116 | while (blockingQueue.size() > 0) { 117 | // 先睡眠 , 然后再进行添加, 防止某些时刻帧不足 , 占用极高的进程持续的访问锁, 浪费资源 118 | try { 119 | Thread.sleep(1000); 120 | } catch (InterruptedException e) { 121 | throw new RuntimeException(e); 122 | } 123 | Process poll = blockingQueue.poll(); 124 | allocate(poll); 125 | } 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /进程调度算法/Java/com/dhx/algorithms/MLFQ.java: -------------------------------------------------------------------------------- 1 | package com.dhx.algorithms; 2 | 3 | import com.dhx.model.Constant; 4 | import com.dhx.model.Process; 5 | 6 | import java.text.SimpleDateFormat; 7 | import java.util.*; 8 | 9 | /** 10 | * @author adorabled4 11 | * @className MLFQ 多级反馈队列调度算法(Multi-Level Feedback Queue) 12 | * @date : 2023/05/21/ 10:29 13 | **/ 14 | public class MLFQ { 15 | 16 | /** 17 | * 累计的程序数量 18 | */ 19 | int totalProcessNum; 20 | 21 | /** 22 | * 已经执行的程序数量 23 | */ 24 | int completedNum; 25 | /** 26 | * 就绪队列 27 | */ 28 | Process running; 29 | 30 | /** 31 | * 多级队列 32 | */ 33 | private List> multiQueue; 34 | 35 | 36 | /** 37 | * 每个队列的时间片大小 38 | */ 39 | private int[] quantum; 40 | 41 | public MLFQ(int numQueues, int[] quantum) { 42 | this.multiQueue = new ArrayList<>(); 43 | for (int i = 0; i < numQueues; i++) { 44 | multiQueue.add(new LinkedList<>()); 45 | } 46 | this.quantum = quantum; 47 | } 48 | 49 | /** 50 | * 添加进程 51 | * 52 | * @param p 进程 53 | */ 54 | public void addProcess(Process p) { 55 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()) + 56 | "\33[35;1m[ARRIVE]进程到达\33[0m, 进程ID :" + p.getPID() + " 预计用时: " + p.getRunTime() + "(s)"); 57 | p.setStatus(Process.READY); 58 | p.setArriveTime(new Date()); // 设置到达时间 59 | // 如果当前的就绪队列已满, 那么把程序添加到阻塞队列(实际上的作用相当于挂载:suspend) 60 | multiQueue.get(0).addLast(p); 61 | totalProcessNum++; 62 | } 63 | 64 | /** 65 | * 执行进程 66 | */ 67 | public void executeProcess() { 68 | while (true) { 69 | int queueIndex = getNextQueueLevel(); 70 | if(queueIndex==-1){ 71 | break;// 所有级的队列都为空 , 结束执行 72 | } 73 | LinkedList currentQueue= multiQueue.get(queueIndex); 74 | while(currentQueue.size()!=0){ 75 | // 获取需要执行的进程 76 | this.running=currentQueue.poll(); 77 | running.setStatus(Process.RUNNING); 78 | long runTime = running.getRunTime(); 79 | try { 80 | if (runTime > quantum[queueIndex]) { 81 | Thread.sleep(quantum[queueIndex] * 1000); 82 | runTime=runTime - quantum[queueIndex]; 83 | running.setRunTime(runTime); 84 | // 将进程加入下一级队列 85 | if(queueIndex+1>=multiQueue.size()){ 86 | // 动态扩容multiQueue , 需要更新时间片数组 87 | multiQueue.add(new LinkedList<>()); 88 | int[] newQuantum = Arrays.copyOf(quantum, multiQueue.size() + 1); 89 | newQuantum[multiQueue.size()-1]=newQuantum[multiQueue.size()-2]+1; 90 | quantum=newQuantum; 91 | } 92 | multiQueue.get(queueIndex + 1).offer(running); 93 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()) + 94 | "\u001B[32m\u001B[1m[LACK]\u001B[0m时间片耗尽, 进程ID :" + running.getPID() + 95 | "\t耗时: " + quantum[queueIndex] + "(s)" + 96 | "添加进程到第 " + (queueIndex + 2) + " 级队列"); 97 | } else { 98 | Thread.sleep(running.getRunTime() * 1000); 99 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss").format(new Date()) + 100 | "\33[92;1m[FINISH]\33[0m执行完毕 进程ID :" + running.getPID() + 101 | "\t耗时: " + running.getRunTime() + "(s)"); 102 | completedNum++; 103 | } 104 | } catch (Exception e) { 105 | System.out.println(new SimpleDateFormat("MM-dd hh:mm:ss") + " 执行进程出现异常"+queueIndex + running); 106 | e.printStackTrace(); 107 | } 108 | } 109 | } 110 | } 111 | 112 | /** 113 | * 获取下一个不为空的队列的级别 114 | * @return 115 | */ 116 | public int getNextQueueLevel(){ 117 | int queueLevel= 0; 118 | while(multiQueue.get(queueLevel).size()==0){ 119 | queueLevel++; 120 | if(queueLevel>=multiQueue.size()){ 121 | return -1; 122 | } 123 | } 124 | return queueLevel; 125 | } 126 | 127 | /** 128 | * 开始执行 129 | */ 130 | public void start() { 131 | while (true) { 132 | try { 133 | Thread.sleep(100); 134 | } catch (InterruptedException e) { 135 | throw new RuntimeException(e); 136 | } 137 | executeProcess(); 138 | } 139 | } 140 | } 141 | --------------------------------------------------------------------------------