CPU调度算法

本文详细介绍了先来先服务(FCFS)、最短作业优先(SJF)、优先级调度(PS)和轮转调度(RR)四种调度算法的原理、实现方式,以及它们在进程调度中的应用场景和优缺点。通过实例演示和代码展示,帮助读者理解调度算法在操作系统中的实际操作。
摘要由CSDN通过智能技术生成

目录

先来先服务调度(First-Come-First-Served, FCFS)

最短作业优先调度(Shortest-Job-First, SJF)

优先级调度(Priority-Scheduling, PS)

轮转调度(Round-Robin, RR)


先来先服务调度(First-Come-First-Served, FCFS)

  • 非抢占(FCFS)

最短作业优先调度(Shortest-Job-First, SJF)

  • 非抢占(nonpremptive_SJF)
  • 抢占(premptive_SJF)

优先级调度(Priority-Scheduling, PS)

  • 非抢占(nonpremptive_PS)
  • 抢占(premptive_PS)

轮转调度(Round-Robin, RR)

  • 抢占(RR)

例子

甘特图


说明

  1. 为了简便起见,所有进程只保留与调度算法相关的属性,即进程号、到达时间、剩余执行时间、已经执行时间、已经等待时间(未使用)、优先级。
  2. 用单向链表表示队列。
  3. 为了简便起见,进程要么处于运行状态,要么在队列中等待状态,同一时刻只有一个进程处于运行状态。
  4. 为了简便起见,在初始时刻,无论进程是否到达,先把所有进程加入队列(不足之处)。
  5. 记当前时间为timer,用来与进程到达时间进行比较,判断进程是否到达。
  6. 假设进程下一次CPU执行时间(CPU burst)已经知道。
  7. 用户只能设置静态优先级nice,而动态优先级priority通过计算得出(只进行简单的模拟)。nice用低数字表示高优先级。

缺点

  • 优先级反转问题没有解决

代码

process.h

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>

#define NZERO 20
#define PRI_USER_MAX 127
#define PRI_USER_MIN 0

typedef struct{
    int pid;                                // 进程号
    int arrival_time;                       // 到达时间
    int remaining_execution_time;           // 剩余执行时间
    int execution_time;                     // 已经执行时间
    int waiting_time;                       // 已经等待时间
    int nice;                               // 静态优先级(数值越低,优先级越高)
    int priority;                           // 动态优先级(数值越高,优先级越高)
}process;

process create_process();                           // 创建一个进程
void setpriority(process *p, int prio);             // 设置静态优先级(-NZERO, NZERO - 1)
int getpriority(process *p);                        // 获取静态优先级
void running_process(process *p);                   // 运行一个时间片
void waiting_process(process *p);                   // 等待一个时间片

process create_process(){
    printf("creating a process....\n");
    process p;
    printf("input pid of process: ");
    scanf("%d", &p.pid);
    printf("input arrival time of the process: ");
    scanf("%d", &p.arrival_time);
    printf("input remaining execution time of the process: ");
    scanf("%d", &p.remaining_execution_time);
    if(p.remaining_execution_time <= 0){
        printf("create process error! Remaining execution time <= 0");
        exit(-1);
    }
    p.execution_time = 0;
    p.waiting_time = 0;
    printf("input priority of the process: ");
    int prio;
    scanf("%d", &prio);
    setpriority(&p, prio);
    p.priority = PRI_USER_MAX - p.execution_time / 4 - p.nice * 2;
    return p;
}

void setpriority(process *p, int prio){
    if(prio < 0 || prio >= 2*NZERO){
        printf("setpriority error!");
        exit(0);
    }
    p->nice = prio - NZERO;
}

int getpriority(process *p){
    return p->nice + NZERO;
}

void running_process(process *p){
    printf("running process %d......\n", p->pid);
    // 更新剩余执行时间和已经执行时间,和动态优先级
    // sleep(1);
    p->remaining_execution_time--;
    p->execution_time++;
    p->priority = PRI_USER_MAX - p->execution_time / 4 - p->nice * 2;
}

void waiting_process(process *p){
    // 更新等待时间
    // sleep(1);
    p->waiting_time++;
}

process_queue.h

#include"process.h"

typedef struct node{
    process value;
    struct node *next;
}node;

typedef struct{
    node *head;         // 头节点
    node *tail;         // 尾节点
    node *curr;         // 当前节点(为了方便进行插入或删除操作,实际上操作的是当前节点的下一个节点)
    int count;          // 链表当前节点数(空节点除外)
}process_queue;

process_queue create();                                         // 创建链表
void clear(process_queue *q);                                   // 清空链表
void append(process_queue *q, process value);                   // 在链表末尾添加节点
void insert(process_queue *q, process value);                   // 在当前位置插入节点
process delete(process_queue *q);                               // 在当前位置删除节点
void moveToStart(process_queue *q);                             // 移到表头
void moveToEnd(process_queue *q);                               // 移到表位
void moveToPos(process_queue *q, int pos);                      // 移到指定位置(pos从0开始)
int currPos(process_queue q);                                   // 当前位置
void next(process_queue *q);                                    // 当前位置向后移
process getValue(process_queue q);                              // 获取当前节点的元素

process FCFS_POP(process_queue *q, int timer);                              // 最先到达的进程
process SJF_POP(process_queue *q, int timer);                               // 剩余执行时间最短的进程
process PS_POP(process_queue *q, int timer);                                // 优先级最高的进程
process RR_POP(process_queue *q, int timer);                                // 轮流执行
void waiting_queue(process_queue *q);                                       // 队列中所有进程等待一个时间片


void init(process_queue *q){
    // 当链表为空时,头节点、尾节点、当前节点无处可指,在插入删除操作时,需要增加额外的代码。
    // 为此,增加一个空节点
    node *n = (node *)malloc(sizeof(node));
    n->next = NULL;
    // 头节点,尾节点,当前节点指向空节点
    q->head = n;
    q->curr = n;
    q->tail = n;
    q->count = 0; 
}

void removeall(process_queue *q){
    // 只要链表不为空,不断地从头删除节点
    while(q->head != NULL){
        q->curr = q->head;
        q->head = q->head->next;
        free(q->curr);
    }
}

process_queue create(){  
    process_queue *q = (process_queue *)malloc(sizeof(process_queue));
    init(q);
    return *q;
}

void clear(process_queue *q){
    removeall(q);
    init(q);
}

void append(process_queue *q, process value){
    node *n = (node *)malloc(sizeof(node));
    n->value = value;
    n->next = NULL;
    // 让链表尾节点指向它(注意指针与实际物理内存的联系,不然会产生疑惑)
    q->tail->next = n;   
    q->tail = q->tail->next;
    q->count++;
}

void insert(process_queue *q, process value){
    node *n = (node *)malloc(sizeof(node));
    n->value = value;
    n->next = q->curr->next;
    q->curr->next = n;
    // 如果当前节点为尾节点,那么尾节点需要指向该节点(尾节点始终应该在链表末尾)
    if(q->curr == q->tail){
        q->tail = q->curr->next;
    }
    q->count++;
}

process delete(process_queue *q){
    // getValue已经判断了是否为空的情况
    process value = getValue(*q);
    node *n = q->curr->next;
    // 如果待删除的节点为尾节点,那么尾节点需要指向当前节点(因为尾节点不应该无处可指)
    if(q->curr->next == q->tail){
        q->tail = q->curr;
    }
    q->curr->next = q->curr->next->next;
    free(n);
    q->count--;
    return value;
}

void moveToStart(process_queue *q){    
    q->curr = q->head;
}

void moveToEnd(process_queue *q){
    q->curr = q->tail;
}

void moveToPos(process_queue *q, int pos){
    if(pos < 0 || pos >= q->count){
        printf("position out of range");
        exit(0);
    }
    moveToStart(q);
    int i = 0;
    while(i < pos){
        q->curr = q->curr->next;
        i++;
    }
}

int currPos(process_queue q){
    node *temp = q.head;
    int i;
    for(i = 0; q.curr != temp; i++){
        temp = temp->next;
    }
    return i;
}

void next(process_queue *q){
    if(q->curr != q->tail){
        q->curr = q->curr->next;
    }
}

process getValue(process_queue q){
    if(q.curr->next == NULL){
        printf("No value");
        exit(0);
    }
    // 返回的是当前节点的下一个节点的值
    return q.curr->next->value;
}

process FCFS_POP(process_queue *q, int timer){
    int pos = 0;    // 记录最先到达的进程所在的位置
    int i = 0;      // 记录当前位置
    int arrival_time = INT_MAX;
    moveToStart(q);
    while(q->curr != q->tail){
        // 只能在已经到达的进程中寻找
        if(getValue(*q).arrival_time <= timer && getValue(*q).arrival_time < arrival_time){
            arrival_time = getValue(*q).arrival_time;
            pos = i;
        }
        i++;
        next(q);
    }
    // 如果当前没有进程,则返回队列中第一个进程
    moveToPos(q, pos);
    return delete(q);
}

process SJF_POP(process_queue *q, int timer){
    int pos = 0;    // 记录剩余执行时间最短的进程所在的位置
    int i = 0;      // 记录当前位置
    int remaining_execution_time = INT_MAX;
    moveToStart(q);
    while(q->curr != q->tail){
        if(getValue(*q).arrival_time <= timer && getValue(*q).remaining_execution_time < remaining_execution_time){
            remaining_execution_time = getValue(*q).remaining_execution_time;
            pos = i;
        }
        i++;
        next(q);
    }
    // 如果当前没有进程,则返回队列中第一个进程
    moveToPos(q, pos);
    return delete(q);
}

process PS_POP(process_queue *q, int timer){
    int pos = 0;    // 记录剩余执行时间最短的进程所在的位置
    int i = 0;      // 记录当前位置
    int priority = INT_MIN;
    moveToStart(q);
    while(q->curr != q->tail){
        if(getValue(*q).arrival_time <= timer && getValue(*q).priority > priority){
            priority = getValue(*q).priority;
            pos = i;
        }
        i++;
        next(q);
    }
    // 如果当前没有进程,则返回队列中第一个进程
    moveToPos(q, pos);
    return delete(q);
}

process RR_POP(process_queue *q, int timer){
    moveToStart(q);
    while(q->curr != q->tail){
        if(getValue(*q).arrival_time <= timer){
            break;
        }
        next(q);
    }
    return delete(q);
}

void waiting_queue(process_queue *q){
    int pos = currPos(*q);
    for(moveToStart(q); q->curr != q->tail; next(q)){
        waiting_process(&(q->curr->value));
    }
    if(pos < q->count){
        moveToPos(q, pos);
    }
}

schedule.h

#include"process_queue.h"

int timer = 0;     // 当前时间

void FCFS(process_queue q);                                 // First-Come-First-Served
void nonpremptive_SJF(process_queue q);                     // nonpremptive Shortest-Job-First
void premptive_SJF(process_queue q);                        // premptive Shortest-Job-First
void nonpremptive_PS(process_queue q);                      // nonpremptive Priority-Scheduling
void premptive_PS(process_queue q);                         // premptive Priority-Scheduling
void RR(process_queue q);                                   // Round-Robin

void FCFS(process_queue q){
    while(q.count > 0){
        // 选择方式--选择队列中第一个到达的进程,直到该进程执行结束
        process p = FCFS_POP(&q, timer);
        // 如果当前没有进程到达
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        while(p.remaining_execution_time > 0){
            // 某一时刻,只有一个进程处于运行状态,其他进程处于等待状态
            running_process(&p);
            waiting_queue(&q);
            timer++;
        }
    }
}

void nonpremptive_SJF(process_queue q){
    while(q.count > 0){
        // 选择方式--选择队列中剩余执行时间最短的进程
        process p = SJF_POP(&q, timer);
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        // 执行该进程直到结束
        while(p.remaining_execution_time > 0){
            // 某一时刻,只有一个进程处于运行状态,其他进程处于等待状态
            running_process(&p);
            waiting_queue(&q);
            timer++;
        }
    }
}

void premptive_SJF(process_queue q){
    while(q.count > 0){
        // 选择方式--选择队列中剩余执行时间最短的进程
        process p = SJF_POP(&q, timer);
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        // 执行该进程一个时间片
        running_process(&p);
        waiting_queue(&q);
        timer++;
        // 如果进程没有执行完成,返回到队列原位置
        if(p.remaining_execution_time > 0){
            insert(&q, p);
        }
    }
}

void nonpremptive_PS(process_queue q){
    while(q.count > 0){
        // 选择方式--选择队列中优先级最高的进程
        process p = PS_POP(&q, timer);
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        // 执行该进程直到结束
        while(p.remaining_execution_time > 0){
            // 某一时刻,只有一个进程处于运行状态,其他进程处于等待状态
            running_process(&p);
            waiting_queue(&q);
            timer++;
        }
    }
}

void premptive_PS(process_queue q){
    while(q.count > 0){
        // 选择方式--选择队列中优先级最高的进程
        process p = PS_POP(&q, timer);
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        // 执行该进程一个时间片
        running_process(&p);
        waiting_queue(&q);
        timer++;
        // 如果进程没有执行完成,返回到队列原位置
        if(p.remaining_execution_time > 0){
            insert(&q, p);
        }
    }
}

void RR(process_queue q){
    while(q.count > 0){
        // 选择方式--轮流执行队列中的进程(队列中第一个到达的进程)       
        process p = RR_POP(&q, timer);
        if(p.arrival_time > timer){
            timer++;
            printf("No process running......\n");
            insert(&q, p);
            continue;
        }
        // 执行该进程一个时间片
        running_process(&p);       
        waiting_queue(&q);
        timer++;
        // 如果进程没有执行完成,返回到队列末尾
        if(p.remaining_execution_time > 0){
            append(&q, p);
        }
    }
}

测试代码

#include"schedule.h"

int main(){
    process p[3];
    process_queue q = create();
    for(int i = 0; i < 3; i++){
        p[i] = create_process();
        append(&q, p[i]);
    }
    // FCFS(q);
    // nonpremptive_SJF(q);
    // premptive_SJF(q);
    // nonpremptive_PS(q);
    // premptive_PS(q);
    RR(q);
    return 0;
}

修改

2021/9/8

轮转调度选择一个进程,执行完一个时间片后,返回队列末尾,而不是原来的位置。这样一来,每次只需要选择队列中第一个到达的进程即可。

2021/9/10

区分了静态优先级和动态优先级,一定程度上(实现的比较粗糙)解决饥饿现象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值