调度的基本概念:从就绪队列中按照一定的算法选择一个进程并将处理机分配给它运行,以实现进程并发地执行。

进程信息

 struct node {
string name;//进程名称
int id;//进程id
int time;//进程服务时间
int rtime;//进程服务时间(主要用于时间片轮转算法)
int level;//进程优先级
int start;//进程提交时间
int lst;//进程调度时间
};
 set<string> pname;//存放进程名称,防止创建重复进程
queue<node> qq;//时间片轮转时用到的就绪队列
queue<node> pp;//进程的执行队列
queue<node> db;//时间片算法中的调度顺序
priority_queue<node, vector<node>, cmpspf> spf;//短时间优先算法队列
priority_queue<node, vector<node>, cmpfpf> fpf;//优先级算法队列
vector<node> ready;//就绪队列
vector<node> emy;//已删除的进程

用vector容器存放就绪的进程(每插入一个,sort一下,依据进程提交时间升序排列)

spf(短作业优先算法)

算法思想:服务时间短的进程在就绪队列前面。

算法规则:要求服务时间最短的进程/作业优先得到服务。

算法实现:模拟时间,将已提交的进程插入优先队列,在依据时间是否到达完成时间来判断哪个进程被移入内存中运行

代码:

 struct cmpspf {
bool operator() (node a, node b) {
if (a.time == b.time)return a.start > b.start;
return a.time > b.time;
}
}; int j = , num = ready.size(),ok=;
sum = -, ans = , avg = 0.00;
//sum作为在执行进程的完成时间
if (t == ) {
for(int i=0;i<=100000;i++) {
if (i == sum) {//首先判断是否到达在执行进程的完成时间
node temp;
temp = spf.top(); spf.pop();
temp.lst = i - temp.start;//计算周转时间
ans += temp.lst;//总的周转时间
avg += double(temp.lst) / double(temp.time);//总的带权周转时间
pp.push(temp);//执行完毕的进程放入执行队列
if (!spf.empty())sum += spf.top().time;
}
while (j < num && i == ready[j].start) {//将到达进程提交时间的进程放入就绪队列
spf.push(ready[j]);
//当CPU执行过程中出现空闲时,更新sum值
if (i > sum&&sum<=spf.top().start)sum = spf.top().start + spf.top().time;
j++;
}
if (ok&&!spf.empty()) {//第一个执行的进程的完成时间
sum = i + spf.top().time;
ok = ;
}
if (j == num && spf.empty())break;//所有进程执行完毕
}
        
printf("进程 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time));
}
printf("平均周转时间为:%.2f\n", double(ans) / double(num));
printf("平均带权周转时间为%.2f\n", avg);

fpf(优先级调度算法)

算法思想:进程优先级高的进程在就绪队列前面。

算法规则:要求进程优先级高的进程/作业优先得到服务。

算法实现:模拟时间,将已提交的进程插入优先队列,在依据时间是否到达完成时间来判断哪个进程被移入内存中运行

代码:逻辑跟spf算法是一样的这里不过多叙述。

 //spf、fpf的区别就在于优先队列中的规则不同
struct cmpfpf {
bool operator() (node a, node b) {
if (a.level == b.level)return a.start > b.start;
return a.level < b.level;
}
};
for(int i=;i<=;i++) {
if (i == sum) {
node temp;
temp = fpf.top(); fpf.pop();
temp.lst = i - temp.start;
ans += temp.lst;
avg += double(temp.lst) / double(temp.time);
pp.push(temp);
if (!fpf.empty())sum += fpf.top().time;
}
while (j < num && i == ready[j].start) {
fpf.push(ready[j]);
if (i > sum&&sum<=fpf.top().start)sum =
fpf.top().start + fpf.top().time;
j++;
}
if (ok&&!fpf.empty()) {
sum = i + fpf.top().time;
ok = ;
}
if (j == num && fpf.empty())break;
}
printf("进程 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst,
double(out.lst) / double(out.time));
}
printf("平均周转时间为:%.2f\n", double(ans) /double(num));
printf("平均带权周转时间为%.2f\n", avg);

时间片轮转算法

算法思想:公平的、轮流的为各个进程服务,让每个进程在一定时间间隔内都可以得到响应

算法规则:系统根据FCFS策略,将所有的就绪进程排成一个就绪队列。

轮流让各个进程执行一个时间片的,若进程未在一个时间片内执行完,则被剥夺处理机,将进程放到就绪队列队尾重新排队。

算法实现:利用队列模拟就绪队列,模拟时间,每次时间增加一个时间片长度,先判断是否有进程在时间片内结束,如果有的话,就对时间进行修改回退到刚完成进程的时间,再判断时间片内是否有进程提交,有的话加入队列。

代码

 printf("请设置时间片大小:\n");
sf(m);
for (int i = ; i <= ; i += m) {//每次自增一个时间片
if (!qq.empty()) {//当运行队列有进程时,则运行该进程
node temp;
temp = qq.front(); qq.pop();
db.push(temp);
if (temp.time > m) {//若进程不能在该时间片内运行完毕,则将服务时间减去时间片,再重新放入队列,这也是使用rtime计算带权周转时间的原因
temp.time -= m;
qq.push(temp);
}
else {//反之回退时间,并将已完成的进程放入执行完毕队列
i =i- m + temp.time;
temp.lst = i - temp.start;
ans += temp.lst;
pp.push(temp);
}
}
while (j < num && i >= ready[j].start) {//到达时间片的进程放入队列
if (ok||qq.empty()) {
i = ready[j].start;
ok = ;
}
ready[j].rtime = ready[j].time;
qq.push(ready[j]);
j++;
}
if (j == num && qq.empty())break;
}
printf("进程调度顺序:\n");
while(!db.empty()){cout<<db.front().name<<" ";db.pop();}
printf("\n进程执行完毕顺序 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.rtime));
avg += double(out.lst) / double(out.rtime);
}
printf("平均周转时间%.2f\n", double(ans) / double(num));
printf("平均带权周转时间为%.2f\n", avg/double(num));

总代码如下:

 #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector<int> vi;
typedef pair<int, int> ii;
#define inf 1e9
#define F first
#define S second
#define dbg(x) cout<<#x<<" value : "<<x<<"\n";
#define rep(i,j,k) for(int i = (j); i <= (k); i++)
#define rep__(i,j,k) for(int i = (j); i < (k); i++)
#define per(i,j,k) for(int i = (j); i >= (k); i--)
#define per__(i,j,k) for(int i = (j); i > (k); i--)
#define mst(a,b) memset(a,b,sizeof(a))
#define sf(n) scanf_s("%d",&n)
#define stf(n,m) scanf("%d%d",&n,&m)
#define pf(n) printf("%d\n",n)
#define slf(n) scanf("%lld",&n)
#define plf(n) printf("%lld\n",n)
const int N = 1e3 + ;
priority_queue<int, vector<int>, less<int> > q;
int t, x, sum, ans, m;
double avg;
string k;
struct node {
string name;//进程名称
int id;//进程id
int time;//进程服务时间
int rtime;//进程服务时间(主要用于时间片轮转算法)
int level;//进程优先级
int start;//进程提交时间
int lst;//进程调度时间
};
struct cmpspf {
bool operator() (node a, node b) {
if (a.time == b.time)return a.start > b.start;
return a.time > b.time;
}
};
struct cmpfpf {
bool operator() (node a, node b) {
if (a.level == b.level)return a.start > b.start;
return a.level < b.level;
}
};
set<string> pname;//存放进程名称,防止创建重复进程
queue<node> qq;//时间片轮转时用到的就绪队列
queue<node> pp;//进程的执行队列
queue<node> db;//时间片算法中的调度顺序
priority_queue<node, vector<node>, cmpspf> spf;//短时间优先算法队列
priority_queue<node, vector<node>, cmpfpf> fpf;//优先级算法队列
vector<node> ready;//就绪队列
vector<node> emy;//已删除的进程
bool cmp(const node& a, const node& b) {
return a.start < b.start;
}
void create() {
node a;
printf("请输入新进程的名称:\n");
cin >> a.name;
if (pname.find(a.name) != pname.end()) {
printf("进程已存在,请从新输入:\n");
create();
return;
}
pname.insert(a.name);
printf("请输入新进程的到达时间、服务时间:\n");
sf(a.start);sf(a.time);
printf("请输入新进程的PID:\n");sf(a.id);
printf("请输入新进程的优先级:\n");sf(a.level);
ready.push_back(a);
sort(ready.begin(), ready.end(), cmp);
}
void kill() {
node b;
printf("请输入要终止的进程名字\n");
cin >> k;
if (pname.find(k) != pname.end()) {
int num = ready.size();
for (int i = ; i < num; i++) {
if (ready[i].name == k) {
b = ready[i];
emy.push_back(b);
ready.erase(ready.begin() + i);
printf("终止进程成功!\n");
}
if (num == ready.size()) {
printf("该进程已在空队列中!\n");
}
}
}
else {
printf("该进程不存在,请输入正确的进程名!\n");
kill();
return;
}
}
void display() {
while (!pp.empty())pp.pop();
while (!spf.empty())spf.pop();
while (!fpf.empty())fpf.pop();
while (!qq.empty())qq.pop();
if (ready.empty()) {
printf("就绪队列为空!\n");
return;
}
printf("请选择调度算法\n");
printf("1、spf调度算法\n");
printf("2、fpf调度算法\n");
printf("3、时间片轮转算法\n");
printf("4、返回菜单\n");
sf(t);
int j = , num = ready.size(),ok=;
sum = -, ans = , avg = 0.00;
//sum作为在执行进程的完成时间
if (t == ) {
rep(i, , ) {
if (i == sum) {//首先判断是否到达在执行进程的完成时间
node temp;
temp = spf.top(); spf.pop();
temp.lst = i - temp.start;//计算周转时间
ans += temp.lst;//总的周转时间
avg += double(temp.lst) / double(temp.time);//总的带权周转时间
pp.push(temp);
if (!spf.empty())sum += spf.top().time;
}
while (j < num && i == ready[j].start) {//将到达进程提交时间的进程放入就绪队列
spf.push(ready[j]);
//当CPU执行过程中出现空闲时,更新sum值
if (i > sum&&sum<=spf.top().start)sum = spf.top().start + spf.top().time;
j++;
}
if (ok&&!spf.empty()) {//第一个执行的进程的完成时间
sum = i + spf.top().time;
ok = ;
}
if (j == num && spf.empty())break;//所有进程执行完毕
}
printf("进程 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time));
}
printf("平均周转时间为:%.2f\n", double(ans) / double(num));
printf("平均带权周转时间为%.2f\n", avg);
}
else if (t == ) {
rep(i, , ) {
if (i == sum) {
node temp;
temp = fpf.top(); fpf.pop();
temp.lst = i - temp.start;
ans += temp.lst;
avg += double(temp.lst) / double(temp.time);
pp.push(temp);
if (!fpf.empty())sum += fpf.top().time;
}
while (j < num && i == ready[j].start) {
fpf.push(ready[j]);
if (i > sum&&sum<=fpf.top().start)sum = fpf.top().start + fpf.top().time;
j++;
}
if (ok&&!fpf.empty()) {
sum = i + fpf.top().time;
ok = ;
}
if (j == num && fpf.empty())break;
}
printf("进程 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.time));
}
printf("平均周转时间为:%.2f\n", double(ans) / double(num));
printf("平均带权周转时间为%.2f\n", avg);
}
else if (t == ) {
printf("请设置时间片大小:\n");
sf(m);
for (int i = ; i <= ; i += m) {//每次自增一个时间片
if (!qq.empty()) {//当运行队列有进程时,则运行该进程
node temp;
temp = qq.front(); qq.pop();
db.push(temp);
if (temp.time > m) {//若进程不能在该时间片内运行完毕,则将服务时间减去时间片,再重新放入队列,这也是使用rtime计算带权周转时间的原因
temp.time -= m;
qq.push(temp);
}
else {//反之回退时间,并将已完成的进程放入执行完毕队列
i =i- m + temp.time;
temp.lst = i - temp.start;
ans += temp.lst;
pp.push(temp);
}
}
while (j < num && i >= ready[j].start) {//到达时间片的进程放入队列
if (ok||qq.empty()) {
i = ready[j].start;
ok = ;
}
ready[j].rtime = ready[j].time;
qq.push(ready[j]);
j++;
}
if (j == num && qq.empty())break;
}
printf("进程调度顺序:\n");
while (!db.empty()) { cout << db.front().name << " "; db.pop(); }
printf("\n进程执行完毕顺序 周转时间 带权周转时间\n");
printf("进程 周转时间 带权周转时间\n");
while (!pp.empty()) {
node out;
out = pp.front(); pp.pop();
cout << out.name;
printf(" %d %.2f\n", out.lst, double(out.lst) / double(out.rtime));
avg += double(out.lst) / double(out.rtime);
}
printf("平均周转时间%.2f\n", double(ans) / double(num));
printf("平均带权周转时间为%.2f\n", avg/double(num));
}
else if (t == ) {
return;
}
else {
printf("输入有误,请按照提示输入:\n");
display();
return;
}
}
inline void meun() {
printf("******************菜单************************\n\n");
printf("********** 1、输入进程 ***************\n");
printf("********** 2、输出队列 ***************\n");
printf("********** 3、终止进程 ***************\n");
printf("********** 4、退出程序 ***************\n");
}
void solve() {
while () {
meun();
sf(x);
switch (x) {
case :
create();
break;
case :
display();
break;
case :
kill();
break;
case :
return;
default:
printf("请按照提示信息进行输入\n");
break;
}
}
return;
} int main()
{
solve();
return ;
}

可以补充的地方,阻塞进程,加入新的vector,每阻塞一个进程,就将其在ready中删除放入新的vector中,唤醒时在阻塞队列中找到该进程,将其移回ready队列。

其实代码写的不是很漂亮,懒省事用了stl,没写链表,时间也是模拟出来的跟真实情况有很大差别,实现的效率也不高(进程少了还行,多了就挺耗时间的,草率地说是O(log(n!)的算法)。这次代码实现的三种算法都是非抢占式的算法,实际情况要比这复杂的多,代码仅供参考,欢迎大家提意见。

优点就是容易想,算是非常暴力的模拟了;能随便加进程,不断更新调度顺序。以后看情况会把程序给完善完善。

进程调度算法spf,fpf,时间片轮转算法实现的更多相关文章

  1. Java实现进程调度算法(二) RR(时间片轮转)

    一.概述 因为这次os作业对用户在控制台的输入输出有要求,所以我花了挺多的代码来完善控制台的显示. 也因为我这次要实现多个类似算法,所以将一些共性单独提取出来作为一个类. 如果只想要和算法有关的核心代 ...

  2. 《操作系统_时间片轮转RR进程调度算法》

    转自:https://blog.csdn.net/houchaoqun_xmu/article/details/55540250 时间片轮转RR进程调度算法 一.概念介绍和案例解析时间片轮转法 - 基 ...

  3. Linux 常见的进程调度算法

    1.在介绍进程调度之前,先对进程的状态的概念应该有所了解,下面是关于进程状态的一些基本概念:进程的状态分为三种,分别为: 1).运行态:该状态表明进程在实际占用CPU 2).就绪态: 该状态下进程可以 ...

  4. 进程调度算法Linux进程调度算法

    这次介绍一下操作系统的进程调度算法 操作系统的调度分为三种:1.远程调度(创建新进程):2.中程调度(交换功能的一部分):3.短程调度(下次执行哪个进程) 这次讲述的就是短程调度,可以简单的看作咱们平 ...

  5. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  6. Linux常见的进程调度算法

    进程调度:在操作系统中调度是指一种资源分配. 调度算法是指: 根据系统的资源分配策略所规定的资源分配算法. 操作系统管理了系统的有限资源,当有多个进程(或多个进程发出的请求)要使用这些资源时,因为资源 ...

  7. os的进程调度算法(抄袭的)

    package me.letterwish.test; import java.io.BufferedInputStream; import java.io.FileInputStream; impo ...

  8. Linux内核初探 之 进程(三) —— 进程调度算法

    一.基本概念 抢占 Linux提供抢占式多任务,基于时间片和优先级对进程进行强制挂起 非抢占的系统需要进程自己让步(yielding) 进程类型 IO消耗型 经常处于可运行态,等待IO操作过程会阻塞 ...

  9. Java 实现--时间片轮转 RR 进程调度算法

    时间片轮转(Round-Robin)调度算法是操作系统一种比较公平的进程调度的方式,这种方式使得就绪队列上的所有进程在每次轮转时都可以运行相同的一个时间片. 基本原理 算法实现原理是,按进程到达顺序( ...

随机推荐

  1. Vue常用语法

    一.模板语法 1.双大括号表达式 [语法:] {{exp}} 用于向页面输入数据,即页面显示数据. [举例:] <!doctype html> <html lang="en ...

  2. E203 CSR rtl实现分析

    CSR状态控制寄存器,每个hart都有自己的CSR.对于每个hart,可以配置的状态寄存器是4k.CSR寄存器的功能见:https://www.cnblogs.com/mikewolf2002/p/1 ...

  3. iOS中进程与线程(多线程、主次线程)

    一.什么是线程?什么是多线程?              线程是用来执行任务的,线程彻底执行完任务A才能去执行任务B.为了同时执行两个任务,产生了多线程. 例子: 打开一个音乐软件,用户开辟一个线程A ...

  4. SQL学习_SELECT

    查询列: SQL:SELECT name FROM heros 多列查询: SQL:SELECT name, hp_max, mp_max, attack_max, defense_max FROM ...

  5. python pip 升级 或者换源

    1. 临时换源python -m pip install --upgrade pip -i https://pypi.douban.com/simple pip国内的一些镜像   阿里云  https ...

  6. 洛谷P2260 [清华集训2012]模积和(容斥+数论分块)

    题意 https://www.luogu.com.cn/problem/P2260 思路 具体思路见下图: 注意这个模数不是质数,不能用快速幂来求逆元,要用扩展gcd. 代码 #include< ...

  7. CUDA -- 规约求矩阵的行和

    求矩阵每行的和? 可以把每行放入一个不同线程块,这样行与行之间进行粗粒度的并行.而对于每行,其对应的线程块中分配n个线程(对应行宽),使用共享存储器,让每个线程从显存中读取一个数至shared mem ...

  8. jquery设置下拉框selected浏览器兼容方式

    今天开发过程中偶然发现一个浏览器兼容性问题 当在某些浏览器下面时使用下面的语法会导致值虽然选中了,但是文本没有切换 var options = $("#select").find( ...

  9. 03webpack--输入webpack--自动打包

    如何实现时时跟新我写的代码 此时就需要有一个配置文件了 webpack.config.js这个文件 这个文件是在跟目录下哦 webpack是基于node去构建的 所以你的依法和node还是很相似的哦 ...

  10. C++中的异常处理(下)

    array.h #ifndef _ARRAY_H_ #define _ARRAY_H_ #include <stdexcept> using namespace std; template ...