进程算法调度-动态优先级

目录

1.实验目的

2.实验内容

3.实验过程

3.1Linux下编写调试程序

3.2编译

3.3实验结果

4.实验详细过程

4.1实验代码整体思路介绍

4.2实验代码详细介绍

5.实验结论


1.实验目的

(1)加深对进程概念的理解,明确进程和程序的区别。

(2)深入理解系统如何组织进程。

(3)理解常用进程调度算法的具体实现。

2.实验内容

编写 C 程序,模拟实现单处理器系统中的进程调度算法,实现对多个进程的模拟调度,要求采用常见的进程调度算法(动态优先级时间片轮转)进行模拟调度。

流程图如下

3.实验过程

3.1Linux下编写调试程序

//动态优先级调度
#include "stdio.h" 
#include <stdlib.h> 
#define getpch(type) (type*)malloc(sizeof(type)) 

struct pcb { /* 定义进程控制块PCB */ 
  char name[10]; //进程名
  char state;    //进程状态:"W"-就绪态,"R"-运行态
  int nice;      //进程优先级
  int ntime;     //需要运行时间
  int rtime;     //已经运行的时间
  struct pcb* link; 
}*ready=NULL,*p; 
typedef struct pcb PCB; 

char sort() /* 建立对进程进行优先级排列函数,优先数大者优先*/ 
{ 
  PCB *first, *second; 
  int insert=0; 
  if((ready==NULL)||((p->nice)>(ready->nice)))/*优先级最大者,插入队首*/ 
  { 
    p->link=ready; 
    ready=p; 
  } 
  else /* 进程比较优先级,插入适当的位置中*/ 
  { 
    first=ready; 
    second=first->link; 
    while(second!=NULL) 
    { 
      if((p->nice)>(second->nice)) /*若插入进程比当前进程优先数大,*/ 
      { /*插入到当前进程前面*/ 
        p->link=second; 
        first->link=p; 
        second=NULL; 
        insert=1; 
      } 
      else /* 插入进程优先数最低,则插入到队尾*/ 
      { 
        first=first->link; 
        second=second->link; 
      } 
    } 
    if(insert==0) first->link=p; 
  } 
} 

char input() /* 建立进程控制块函数*/ 
{ 
  int i,num; 
  printf("\n 请输入被调度的进程数目:"); 
  scanf("%d",&num); 
  for(i=0;i<num;i++) 
  { 
    printf("\n 进程号No.%d:",i); 
    p=getpch(PCB); 
    printf("\n 输入进程名:"); 
    scanf("%s",p->name); 
    printf(" 输入进程优先数:"); 
    scanf("%d",&p->nice); 
    printf(" 输入进程运行时间:"); 
    scanf("%d",&p->ntime); 
    printf("\n"); 
    p->rtime=0;
    p->state='W'; 
    p->link=NULL; 
    sort(); /* 调用sort函数*/ 
  } 
} 

int space() 
{ 
  int l=0; PCB* pr=ready; 
  while(pr!=NULL) 
  { 
    l++; 
    pr=pr->link; 
  } 
  return(l); 
} 

char disp(PCB * pr) /*建立进程显示函数,用于显示当前进程*/ 
{ 
  printf("\n qname \t state \t nice \tndtime\truntime \n"); 
  printf("%s\t",pr->name); 
  printf("%c\t",pr->state); 
  printf("%d\t",pr->nice); 
  printf("%d\t",pr->ntime); 
  printf("%d\t",pr->rtime); 
  printf("\n"); 
}

char check() /* 建立进程查看函数 */ 
{ 
  PCB* pr; 
  printf("\n **** 当前正在运行的进程是:%s",p->name); /*显示当前运行进程*/ 
  disp(p); 
  pr=ready; 
  if (pr!=NULL) 
    printf("\n ****当前就绪队列状态为:"); /*显示就绪队列状态*/
  else 
    printf("\n ****当前就绪队列状态为: 空\n"); /*显示就绪队列状态为空*/
  while(pr!=NULL) 
  { 
    disp(pr); 
    pr=pr->link; 
  } 
} 

char destroy() /*建立进程撤消函数(进程运行结束,撤消进程)*/ 
{ 
  printf(" 进程 [%s] 已完成.\n",p->name); 
  free(p); 
}
 
char running() /* 建立进程就绪函数(进程运行时间到,置就绪状态*/ 
{ 
  (p->rtime)++; 
  if(p->rtime==p->ntime) 
  destroy(); /* 调用destroy函数*/ 
  else 
  { 
    (p->nice)--; 
    p->state='W'; 
    sort(); /*调用sort函数*/ 
  } 
} 

int main() /*主函数*/ 
{ 
  int len,h=0; 
  char ch; 
  input(); 
  len=space(); 
  while((len!=0)&&(ready!=NULL)) 
  { 
    ch=getchar(); 
    h++; 
    printf("\n The execute number:%d \n",h); 
    p=ready; 
    ready=p->link; 
    p->link=NULL; 
    p->state='R'; 
    check(); 
    running(); 
    printf("\n按任一键继续......"); 
    ch=getchar(); 
  } 
  printf("\n\n 所有进程已经运行完成!\n"); 
  ch=getchar(); 
  return 0;
}

创建schedule.c文件

Linux下编写代码

3.2编译

使用gcc命令编译

3.3实验结果

后面同样的道理

4.实验详细过程

4.1实验代码整体思路介绍

(1)算法过程

我们实验的算法主要涉及的是动态优先级进程调度的原理,其原理大概如下。

(2)针对此过程,使用了如下函数

  • input()主要作为初始化

  • sort()用于进程入就绪队列

  • space()求取就绪队列中元素的个数

  • check()显示正在运行和处于就绪队列进程的一个情况

  • disp()显示单个进程状态

  • running()模拟进程运行过程

  • destory()销毁进程(销毁节点)

4.2实验代码详细介绍

(1)基本头文件的引入和结构体的声明

​
#include "stdio.h" //引入头文件用于标准输入输出
#include <stdlib.h> //动态内存管理的库函数
#define getpch(type) (type*)malloc(sizeof(type))//这句代码的意思是
//我将动态分配内存的代码(类型*)malloc(sizeof(类型))用getch(类型)来代替,
//目的是为了以下代码简写,比如在后面代码中出现的:p=getpch(PCB);  
/*这一块的作用就是定义一个数据结构用于存放进程*/
struct pcb { /* 定义进程控制块PCB */ 
  char name[10]; //进程名
  char state;    //进程状态:"W"-就绪态,"R"-运行态
  int nice;      //进程优先级
  int ntime;     //需要运行时间
  int rtime;     //已经运行的时间
  struct pcb* link; //指向下一个进程控制块,用于构建就绪队列。
}*ready=NULL,*p; //ready 是一个全局指针,它作用是始终指向就绪队列的头部
//p 是一个临时指针,通常用于局部操作(如遍历链表、分配新节点等)。

​

(2)main函数中首先介绍基本的变量,比如len用于记录进程个数,h用于记录进程运行次数,具体的函数调用将在后面详细解释

/*主函数最大的作用就是while循环部分了
1)我首先定义一个len和h,len用于记录进程个数,h用于记录进程运行的次数
2)我需要一个char类型的字符ch来接受getchar()函数的返回值,这样做的目的是为了用户进行交互
3)我完成这个模拟第一步就是调用input()函数进行初始化操作,该操作的具体完成在后面(3)中讲。
4)之后我们调用space()函数先计算出就绪队列中进程个数并把值存在len中,它的作用就是为了当while循环的判断条件
5)接下来核心就是while循环了
  1.1首先看条件(len!=0)&&(ready!=NULL)
      len:表示就绪队列中的进程数量,通过 space() 函数计算。
      如果 len 不为 0,表示就绪队列中还有进程等待调度。
      如果 len 为 0,表示就绪队列为空,所有进程已经完成。
      len != 0 从数量上判断是否还有进程。
      ready != NULL 从指针上判断是否还有进程。
      两者结合,确保循环的正确性,这个没有什么可争议的。
  1.2其次while中核心代码有三部分,其余都是修饰可有可无,没必要解释
    第一部分:
        p=ready; 
        ready=p->link; 
        p->link=NULL; 
        p->state='R'; 
        意思就是我从就绪队列中拿出头节点(第一个进程)让他
        处于一个运行状态(当然此进程状态也修改为运行态R),
        那么既然此进程运行了我就让他不要在就绪队列中,
        此时我使用临时变量p完成队列的头删法:
        p=ready; 
        ready=p->link; 
        p->link=NULL;这三句便是头删的核心代码。
     第二部分
        check();
        调用该函数打印以上操作过后进程运行和就绪状态情况
     第三部分:
        running()
        该函数就是来事实更改进程运行的信息的,也就是模拟进程的过程
        他的一个思想就是:(注意:此思想在(8)中有解释)
        1.你当前进程运行了我就让你已运行时间rtime+1
        2.并且我判断从始至终这个进程已运行时间rtime是否==此进程完成需要的时间ntime,
          如果相等就调用destory()将他销毁。
        3.否则我就让此进程优先级nice-1并将状态改为w,然后让他进入就绪队列
*/
int main() /*主函数*/ 
{ 
  int len,h=0; //len用于记录进程个数,h用于记录进程运行的次数
  char ch; 
  input(); 
  len=space(); 
  while((len!=0)&&(ready!=NULL)) 
  { 
    ch=getchar(); //用于用户交互不用在意
    h++; //进程运行次数加1
    printf("\n The execute number:%d \n",h); //输出进程运行次数
    p=ready; 
    ready=p->link; 
    p->link=NULL; 
    p->state='R'; 
    check(); 
    running(); 
    printf("\n按任一键继续......"); 
    ch=getchar(); 
  } 
  printf("\n\n 所有进程已经运行完成!\n"); 
  ch=getchar(); 
  return 0;
}

(3)input函数,此函数主要就是起着一个创建进程并初始化的作用,他需要用户自己输入所要创建的进程数并且此函数还调用sort()函数对进程进行优先级排列


(4)sort()函数主要目的就是你这个进程的优先级来从小到大的入队列,那么也因此有四种情况:

  • 首进程入队(首元素入队列)

  • 头插

  • 合适位置插入队列

  • 尾插

这四种情况将会在如下图示中体现


(5)sapce()求取就绪队列中的进程个数用于判断进程是否已经结束了


(6)此时回到主函数的while部分进行程序调度,将正在执行的进程从就绪队列中剔除,然后调用check()输出信息,以及调用running()进行判断进程是否结束和是否进入就绪队列,当然这一点也是刚刚在main方法中的说过思想,这里只是为了提供数据结构。


(6)check()和disp()配合使用用于形如以下格式的显示,这两个函数中的代码就单纯是做输出的操作全是printf函数,没什么可说的


(8)running()他的作用就是一个模拟进程的运行过程。

在此期间:

  • 已运行rtime加1;
  • 并且如果已运行时间等于需要运行时间说明该进程已经完成了,此时就应该调用destory()将他销毁,说白了就是if(p->rtime==p->ntime){destory();}
  • 否则,就优先级减1,然后调用sort()函数再重新排到就绪队列中,说白了就是else{(p->nice)--;p->state='w';sort();}


(9)destory()这个函数就是对我们创建的进程进行销毁,防止占用资源


(10)至此动态优先级的代码解释完毕,总结就是,本算法主要是实现动态优先级的模拟,但是也有时间片轮转的调度,比如running()中的p->rtime==p->ntime就有体现。


5.实验结论

  1. 基本思想:为每个进程设置一个优先级,在调度的时候,选取优先级最大的任务去执行。
  2. 优先级可以是静态赋予:创建任务的时候,就指定优先级大小,并且保持不变,直到任务结束。
  3. 也可以是动态赋予:优先级在执行任务中动态改变。
  4. 为了防止高优先级进程无休止地运行下去,调度程序可以在每个时钟中断降低当前进程的优先级。
  5. 在平时中,我们可以把不同的任务划分为不同的优先级,然后在相同优先级的任务中使用时间片轮转。
### 优先级调度算法的实现与工作原理 #### 高优先级队列机制 优先级调度的核心在于通过定义不同优先级来管理进程。具有较高优先级的任务会被安排到高优先级队列中,而低优先级任务则进入较低级别的队列[^1]。 #### 抢占式与非抢占式的区别 - **抢占式优先级调度**:当有新的更高优先级任务到达时,当前正在运行的任务会被中断并重新放入等待队列中,随后由新到来的高优先级任务继续执行。 - **非抢占式优先级调度**:一旦某个任务开始执行,则它会持续占用处理器直到完成或者主动释放资源为止,即使期间可能出现了其他更紧急的需求也不会被打断。 #### 时间片轮转结合方法 为了进一步优化性能表现以及公平性考量,在某些场景下可以将时间片轮转技术引入至各层优先级队列内部操作流程当中去。这意味着即便处于同一级别内的多个作业之间也需要按照固定时间段依次交替获得CPU使用权。 以下是基于上述描述的一个简单模拟版本代码示例: ```c #include<stdio.h> struct Process { int pid; float priority; }; void sortProcesses(struct Process proc[],int n){ struct Process temp; for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) if(proc[i].priority<proc[j].priority){ temp = proc[i]; proc[i]=proc[j]; proc[j]=temp; } } int main(){ printf("请输入总共有多少个进程:"); int num; scanf("%d",&num); struct Process processes[num]; for (int i = 0; i < num; ++i) { printf("\n输入第%d个进程ID及其对应的优先级:",i+1); scanf("%d%f", &processes[i].pid,&processes[i].priority ); } // 对所有进程按其设定好的优先度降序排列起来以便后续处理调用顺序更加合理化些吧? sortProcesses(processes ,num); printf("\n\n经过排序后的最终结果如下所示:\n"); for(int k=0;k<num;k++){ printf("Process ID:%d\tPriority Value:%f \n ",processes[k].pid,processes[k].priority ); } return 0;} ``` 此段C语言脚本展示了如何创建结构体表示单个进程对象属性信息(这里仅考虑到了编号id跟权重值两个维度),并通过冒泡法对其进行初步整理分类从而达成预期目标效果——即让那些拥有较大数值代表重要程度较高的项目能够尽早得到服务响应机会[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值