这个是我一次的操作系统作业,在赶ddl的过程中临时产生的一种比较特别的实现思路,在此处分享。
这里的算法都是非抢占式,由于我本人比较懒,所以这里只有一些比较简单的算法。但是因为这个思路比较清奇,所以在此记录一下:
先来先服务算法
这个是实验中已经提供的算法,思路比较简单,就是直接比较几个进程的到达时间,谁最先到达就先服务,先到先得,而且是非抢占式,所以这里的实现非常的简单,代码如下:
void FCFS()
{
int i, j, temp;
double k;
for(i = 0; i < num; i++)
{
order[i] = pcbdata[i].time_start;
ready[i] = i;
}
for(i = 0; i < num;i++) // 简单冒泡排序
{
for(j = i + 1; j < num; j++)
{
if(order[i] > order[j])
{
temp = order[i];
order[i] = order[j];
order[j] = temp;
temp = ready[i];
ready[i] = ready[j];
ready[j] = temp;
}
}
}
printf("FIFO running...\n");
temp =pcbdata[ready[0]].time_start;
for(i = 0;i < num;++i){
printf("第%d个进程-- %s:",i+1,pcbdata[ready[i]].name);
printf("到达时间: %d, 服务时间: %d\n",pcbdata[ready[i]].time_start,pcbdata[ready[i]].time_need);
printf("本进程正在运行...\n");
_sleep(1);
printf("运行完毕\n");
temp += pcbdata[ready[i]].time_need;
j = temp - pcbdata[ready[i]].time_start;
k = (double)j/pcbdata[ready[i]].time_need;
printf("完成时间: %d, 周转时间: %d, 带权周转时间: %.2lf\n",temp,j,k);
}
printf("所有进程运行完毕.\n");
}
这里代码比较捞,没有用到比较方便的STL
以及sort
函数,后面的算法中需要用到队列,这里用数组来模拟这个队列。
短作业优先算法
短作业优先在上面先来先服务算法的基础上,加了一个对服务时间进行排序的过程,每一次找队列中服务时间最短的作业进行调度。这里就存在这么一个问题,我们不能像上面的实现直接对到达时间进行排序了那样对服务时间进行排序,因为这里也要遵循一个先来先到的原则。
这个就是本次激发我思路的地方,由于这里没有队列,所以想到用数组模拟队列,这里我将数组用两个指针分为三个部分,就像下面这个图一样。
而筛选最小运行时间的任务的工作,只需要在已入队列的部分中进行排序即可。所以这里整个算法的流程如下:
- 先对所有的任务的到达时间进行排序。
- 初始化三个部分的分割指针,初始化为0。初始化开始的时间
- 从未入队列部分中找出所有时间中等于当前任务的到达时间的任务(处理到达时间相同的情形),将其入队列。调整两个指针。
- 在两个指针中进行排序,得到以运行时间排序的队列
- 出队列头部处理任务,回到步骤3.
实现代码如下:
void SJF() // 短作业优先算法
{
int ele_num_begin_pointer = 0;
int ele_num_end_pointer = 0;
int i, j, temp, t;
double k;
for(i = 0; i < num; i++)
{
order[i] = pcbdata[i].time_start;
order2[i] = pcbdata[i].time_need;
ready[i] = i;
}
for(i = 0; i < num;i++)
{
for(j = i + 1; j < num; j++)
{
if(order[i] > order[j])
{
temp = order[i];
order[i] = order[j];
order[j] = temp;
temp = ready[i];
ready[i] = ready[j];
ready[j] = temp;
temp = order2[i];
order2[i] = order2[j];
order2[j] = temp;
}
}
}
printf("SJF running...\n");
temp =pcbdata[ready[0]].time_start;
while(ele_num_begin_pointer < num)
{
int cnt = 0;
for(i = ele_num_end_pointer; i < num; i++)
{
if(pcbdata[ready[i]].time_start <= temp)
{
cnt++;
}
}
ele_num_end_pointer += cnt;
// inner sort
for(i = ele_num_begin_pointer; i < ele_num_end_pointer;i++)
{
for(j = ele_num_begin_pointer + 1; j < ele_num_end_pointer; j++)
{
if(order2[i] > order2[j])
{
t = order2[i];
order2[i] = order2[j];
order2[j] = t;
t = ready[i];
ready[i] = ready[j];
ready[j] = t;
}
}
}
// running process
printf("第%d个进程-- %s:",ele_num_begin_pointer+1,pcbdata[ready[ele_num_begin_pointer]].name);
printf("到达时间: %d, 服务时间: %d\n",pcbdata[ready[ele_num_begin_pointer]].time_start,pcbdata[ready[ele_num_begin_pointer]].time_need);
printf("本进程正在运行...\n");
_sleep(1);
printf("运行完毕\n");
temp += pcbdata[ready[ele_num_begin_pointer]].time_need;
j = temp - pcbdata[ready[ele_num_begin_pointer]].time_start;
k = (double)j/pcbdata[ready[ele_num_begin_pointer]].time_need;
printf("完成时间: %d, 周转时间: %d, 带权周转时间: %.2lf\n",temp,j,k);
ele_num_begin_pointer += 1;
}
printf("所有进程运行完毕.\n");
}
你看,这样的思路是不是清晰了许多?
然后还有高响应比算法和时间片轮转算法,都是基于上面的这个模板思路,通过这个双指针滑动窗口的方法可以很好的将进程按照到达时间依次进入数组中。
高响应比优先算法
先来先服务可能会长阻塞,而短作业优先可能长作业一辈子也执行不了,为了解决这个问题,找到了一种折中的方法,那就是高响应比优先调度策略。响应比计算公式如下:
H R F = w a i t + n e e d n e e d = w a i t n e e d + 1 HRF = \frac{wait+need}{need}=\frac{wait}{need}+1 HRF=needwait+need=needwait+1
在上面短作业优先的基础之上,只需要将短作业的选择改为响应比的选择即可。由于这里我使用类似滑动窗口的方法用数组模拟队列,这里将会使得进入调度的任务都是严格按照时间前后进行处理的。这里只需要补充响应比的迭代即可。
时间片轮转算法
时间片轮转策略则是以时间片为一个调度切换周期。当时间片完了之后,进入先来先服务的调度中,当一个任务在时间片完了之后的剩余时间还不是0,则将该任务调度到队列的末尾中。与其他的进程继续在队列中等候处理。
这里同样需要考虑时间的前后问题,所以还是使用前面滑动窗口,数组模拟队列的思路。这里需要补充的就是更新进程pcb的剩余时间,判断时间片完时,是否运行完,如果没有则将其排到队列末尾中。这里的排到末尾步骤只需要在第二个部分中的已入队列部分中进行处理即可。
,则将该任务调度到队列的末尾中。与其他的进程继续在队列中等候处理。
这里同样需要考虑时间的前后问题,所以还是使用前面滑动窗口,数组模拟队列的思路。这里需要补充的就是更新进程pcb的剩余时间,判断时间片完时,是否运行完,如果没有则将其排到队列末尾中。这里的排到末尾步骤只需要在第二个部分中的已入队列部分中进行处理即可。
所有代码:https://download.youkuaiyun.com/download/Dong142857/19160293