【操作系统实验6】CPU调度程序模拟实现

一、实验目标

加深对操作系统CPU调度以及调度算法的理解

二、实验内容

1.思路

1)

  • 单处理器环境下,针对最短作业优先算法(SJF)和优先级调度算法(Priority),分别模拟实现抢占调度和非抢占调度的调度程序
  • 设计使用三个队列,分别为就绪队列(readyQueue)、运行队列(runningQueue)、等待队列(waitingQueue)
  • 进程状态三种,分别为就绪状态:0、运行状态:1、等待状态:2
  • 输入:task.txt 文件和指定调度算法
    • task.txt 文件为需要调度的进程集
    • 非抢占 SJF: sjf
    • 抢占 SJF: psjf
    • 非抢占 Priority: pprio
    • 抢占 Priority: prio
  • 输出:按照所指定的调度算法,显示调度结果
    • 比如:P2:2、P1:2、P3:1、P4:5

2)1数据结构
本次实验的数据结构参考了 pintos 中的线程调度:使⽤ PCB 结构体表示进程、使⽤双向链表管理进程。
PCB 结构体定义如下:

 typedef struct PCB {
 int pid; // pid
 int time_release; // release time
 int time_cpu; // total CPU execution time
 int time_remaining; // remaining CPU execution tine
 int priority; // priority
 enum ProcessState state; // process state

 struct PCB* prev; // previous process pointer
 struct PCB* next; // next process pointer
 } PCB;

为何适配该实验,双向链表上实现了⼀些常⽤的操作函数。由于本实验中需要通过进程的优先级和剩余 CPU 时间进⾏排序,所以还参考 pintos 实现了有序插⼊的操作。

1 /* Operations on list. */
2 List* list_create();
3 void list_delete(List* list);
4
5 /* Iteration operations */
6 ListElem* list_begin(List* list);
7 ListElem* list_next(ListElem* elem);
8 ListElem* list_end(List* list);
9
10 /* Removal operations. */
11 ListElem* list_remove(ListElem* elem);
12 ListElem* list_pop_front(List* list);
13
14 /* Insertion operations. */
15 void list_insert(ListElem* before, ListElem* elem);
16 void list_insert_ordered(List* list, ListElem* elem,
17 list_less_func* less_func);
18 void list_push_back(List* list, ListElem* elem);
19
20 /* Get list properties. */
21 size_t list_size(List* list);
22 int list_empty(List* list);

3)算法
本实验中⾸先计算出运⾏完所有进程所需要的 CPU 区间⻓度 T,然后使⽤ for 循环,令 i 从0 遍历到 T-1 来模拟实际 CPU 调度中定时器产⽣的时间⽚到时中断:i 每增加 1,代表 CPU执⾏了⼀个时间⽚,此时应该重新进⾏调度。
下⾯以最短作业优先调度为例概述调度算法,优先级调度算法与此类似,代码也极其相似。
在⼀个新的时间⽚到来时,将 CPU 分配给哪⼀个进程有两个需要考虑的因素 — 进程的到达时间与进程的剩余 CPU 区间。假如当前到来的是第 i 个时间⽚,只有到达时间(release time)⼩于等于 i 的进程才有机会被分配 CPU;随后我们需要在些进程中选择剩余 CPU 区间最短的作为执⾏进程。
由此得到的结论就是,我们需要先对进程的到达时间作为第⼀优先级、剩余 CPU 区间作为第⼆优先级进⾏排序。本实验采⽤的⽅法是在进程创建的时候就将其按照上述两个优先级插⼊到ready queue 中,使 ready queue 成为⼀个优先级队列。在⾮抢占式调度中,⼀个进程执⾏完⽆需执⾏其他操作;⽽在抢占式调度中,⼀个进程在该时间⽚内执⾏完后,需要判断其剩余 CPU 区间是否为 0,如果为 0,则需要将其重新按照上述两个优先级插⼊到队列中。
同理,如果采⽤优先级调度,上述的排列规则变为到达时间使第⼀优先级,⽽进程优先级是第⼆优先级。

2.代码

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

enum ProcessState {
    PROCESS_READY,
    PROCESS_RUNNING
};

typedef struct PCB {
    int pid;                  
    int time_release;         
    int time_cpu;             
    int time_remaining;       
    int priority;             
    enum ProcessState state;  

    struct PCB* prev;
    struct PCB* next;
} PCB;

typedef PCB ListElem;

typedef struct List {
    ListElem head;
    ListElem tail;
} List;

/* Compares the value of two list elements A and B, given
   auxiliary data AUX.  Returns true if A is less than B, or
   false if A is greater than or equal to B. */
typedef int list_less_func(const ListElem* a,
                           const ListElem* b);

PCB* process_running;
List* ready_queue;
List* terminated_list;

char file_name[] = "sched.txt";
FILE* file;

/* Operations on list. */
List* list_create();
void list_delete(List* list);

ListElem* list_begin(List* list);
ListElem* list_next(ListElem* elem);
ListElem* list_end(List* list);

ListElem* list_remove(ListElem* elem);
ListElem* list_pop_front(List* list);

void list_insert(ListElem* before, ListElem* elem);
void list_insert_ordered(List* list, ListElem* elem,
                         list_less_func* less_func);
void list_push_back(List* list, ListElem* elem);

size_t list_size(List* list);
int list_empty(List* list);

/* Operations on process. */
PCB* process_create(int pid, int time_release, int priority, int time_exec);

void process_sched_sjf(int cpu_time);
void process_sched_psjf(int cpu_time);
int process_cmp_sjf(const ListElem* a, const ListElem* b);

void process_sched_prio(int cpu_time);
void process_sched_pprio(int cpu_time);
int process_cmp_prio(const ListElem* a, const ListElem* b);

void process_print(int cnt);

void print_header(int cpu_time);

int get_total_cpu_time();

PCB* load_process_from_file();

int main() {
    int cpu_time, mode;
    PCB* process;
    file = fopen(file_name, "r");

    ready_queue = list_create();
    terminated_list = list_create();

    printf("Input schedule mode.\n1: sjf, 2: psjf, 3: prio, 4:pprio.\n");
    scanf("%d", &mode);

    switch (mode) {
    case 1: {
        while ((process = load_process_from_file()) != NULL) {
            list_insert_ordered(ready_queue, process, process_cmp_sjf);
        }
        cpu_time = get_total_cpu_time();
        printf("\n\n");
        print_header(cpu_time);
        process_sched_sjf(cpu_time);
        printf("\n\n");
    } break;
    case 2: {
        while ((process = load_process_from_file()) != NULL) {
            list_insert_ordered(ready_queue, process, process_cmp_sjf);
        }
        cpu_time = get_total_cpu_time();
        printf("\n\n");
        print_header(cpu_time);
        process_sched_psjf(cpu_time);
        printf("\n\n");
    } break;
    case 3: {
        while ((process = load_process_from_file()) != NULL) {
            list_insert_ordered(ready_queue, process, process_cmp_prio);
        }
        cpu_time = get_total_cpu_time();
        printf("\n\n");
        print_header(cpu_time);
        process_sched_prio(cpu_time);
        printf("\n\n");
    } break;
    case 4: {
        while ((process = load_process_from_file()) != NULL) {
            list_insert_ordered(ready_queue, process, process_cmp_prio);
        }
        cpu_time = get_total_cpu_time();
        printf("\n\n");
        print_header(cpu_time);
        process_sched_pprio(cpu_time);
        printf("\n\n");
    } break;

    default:
        break;
    }

    list_delete(ready_queue);
    list_delete(terminated_list);

    return 0;
}

List* list_create() {
    List* list = (List*)malloc(sizeof(List));
    if (!list) {
        printf("list_create(): malloc failed.\n");
        exit(1);
    }

    list->head.prev = NULL;
    list->head.next = &list->tail;
    list->tail.prev = &list->head;
    list->tail.next = NULL;

    return list;
}

void list_delete(List* list) {
    ListElem* elem;
    while (!list_empty(list)) {
        elem = list_pop_front(list);
        free(elem);
    }
    free(list);
}

ListElem* list_begin(List* list) {
    return list->head.next;
}

ListElem* list_next(ListElem* elem) {
    return elem->next;
}

ListElem* list_end(List* list) {
    return &list->tail;
}

ListElem* list_remove(ListElem* elem) {
    elem->prev->next = elem->next;
    elem->next->prev = elem->prev;

    return elem->next;
}

ListElem* list_pop_front(List* list) {
    ListElem* front = list_begin(list);
    list_remove(front);

    return front;
}

void list_insert(ListElem* before, ListElem* elem) {
    elem->prev = before->prev;
    elem->next = before;
    before->prev->next = elem;
    before->prev = elem;
}

void list_push_back(List* list, ListElem* elem) {
    list_insert(list_end(list), elem);
}

void list_insert_ordered(List* list, ListElem* elem,
                         list_less_func* less_func) {
    ListElem* e;
    for (e = list_begin(list); e != list_end(list); e = list_next(e))
        if (less_func(elem, e))
            break;
    list_insert(e, elem);
}

size_t list_size(List* list) {
    ListElem* elem;
    size_t cnt = 0;
    for (elem = list_begin(list); elem != list_end(list); elem = list_next(elem))
        cnt++;

    return cnt;
}

int list_empty(List* list) {
    return (list_begin(list) == list_end(list));
}

PCB* process_create(int pid, int time_release, int priority, int time_exec) {
    PCB* process = (PCB*)malloc(sizeof(PCB));
    if (!process) {
        printf("process_create(): malloc failed.\n");
        exit(1);
    }

    process->pid = pid;
    process->time_release = time_release;
    process->time_cpu = time_exec;
    process->time_remaining = time_exec;
    process->priority = priority;
    process->state = PROCESS_READY;

    return process;
}

void process_sched_sjf(int cpu_time) {
    int i = 0;
    PCB* next;

    for (; i < cpu_time; i++) {
        process_running = list_begin(ready_queue);
        for (next = list_next(process_running); next != list_end(ready_queue); next = list_next(next)) {
            if (next->time_release > i)
                break;
            if (next->time_remaining < process_running->time_remaining)
                process_running = next;
        }
        i += process_running->time_remaining - 1;
        list_remove(process_running);
        list_push_back(terminated_list, process_running);
        process_print(process_running->time_remaining);
    }
}

void process_sched_psjf(int cpu_time) {
    int i = 0;
    PCB* next;

    for (; i < cpu_time; ++i) {
        process_running = list_begin(ready_queue);
        for (next = list_next(process_running); next != list_end(ready_queue); next = list_next(next)) {
            if (next->time_release > i)
                break;
            if (next->time_remaining < process_running->time_remaining)
                process_running = next;
        }
        process_running->time_remaining--;
        process_print(1);
        if (process_running->time_remaining > 0) {
            list_remove(process_running);
            list_insert_ordered(ready_queue, process_running, process_cmp_sjf);
        } else {
            list_remove(process_running);
            list_push_back(terminated_list, process_running);
        }
    }
}

int process_cmp_sjf(const ListElem* a, const ListElem* b) {
    if (a->time_release != b->time_release)
        return (a->time_release < b->time_release);
    else
        return (a->time_remaining < b->time_remaining);
}

void process_sched_prio(int cpu_time) {
    int i = 0;
    PCB* next;

    for (; i < cpu_time; i++) {
        process_running = list_begin(ready_queue);
        for (next = list_next(process_running); next != list_end(ready_queue); next = list_next(next)) {
            if (next->time_release > i)
                break;
            if (next->priority < process_running->priority)
                process_running = next;
        }
        i += process_running->time_remaining - 1;
        list_remove(process_running);
        list_push_back(terminated_list, process_running);
        process_print(process_running->time_remaining);
    }
}

void process_sched_pprio(int cpu_time) {
    int i = 0;
    PCB* next;

    for (; i < cpu_time; ++i) {
        process_running = list_begin(ready_queue);
        for (next = list_next(process_running); next != list_end(ready_queue); next = list_next(next)) {
            if (next->time_release > i)
                break;
            if (next->priority < process_running->priority)
                process_running = next;
        }
        process_running->time_remaining--;
        process_print(1);
        if (process_running->time_remaining > 0) {
            list_remove(process_running);
            list_insert_ordered(ready_queue, process_running, process_cmp_prio);
        } else {
            list_remove(process_running);
            list_push_back(terminated_list, process_running);
        }
    }
}

int process_cmp_prio(const ListElem* a, const ListElem* b) {
    if (a->time_release != b->time_release)
        return (a->time_release < b->time_release);
    else
        return (a->priority < b->priority);
}

void process_print(int cnt) {
    int i = 0;
    for (; i < cnt; ++i)
        printf("  P%d  ", process_running->pid);
}

void print_header(int cpu_time) {
    int i = 0;
    for (; i < cpu_time; ++i)
        printf("|_____");
    printf("|\n");

    for (i = 0; i <= cpu_time; ++i)
        printf("%-6d", i);
    printf("\n");
}

int get_total_cpu_time() {
    int total_cpu_time = 0;
    ListElem* elem = list_begin(ready_queue);
    for (; elem != list_end(ready_queue); elem = list_next(elem))
        total_cpu_time += elem->time_remaining;

    return total_cpu_time;
}

PCB* load_process_from_file() {
    int pid, time_release, time_cpu, priority;
    PCB* process = NULL;

    if (fscanf(file, "%d%d%d%d", &pid, &time_release, &priority, &time_cpu) != EOF) {
        process = process_create(pid, time_release, priority, time_cpu);
    }

    return process;
}

3.过程及运行结果展示

从文本文件中输入信息(格式:进程ID, 到达时间, 优先级, 运行时间)
在这里插入图片描述

非抢占式最短作业优先调度
在这里插入图片描述

抢占式最短作业优先调度
在这里插入图片描述

非抢占式优先级调度
在这里插入图片描述

抢占式优先级调度
在这里插入图片描述

三、实验结论

通过本实验对于调度算法有了更加深刻的理解。
-最短作业优先调度:
抢占式:当新进来的进程的CPU区间比当前执行的进程所剩的CPU区间短,则抢占。
非抢占:为下一个最短优先,因为在就绪队列中选择最短CPU区间的进程放在队头。
-优先级调度算法:SJF是特殊的优先级调度算法,以CPU区间长度的倒数为优先级。
抢占式为如果进来的进程优先级高于运行的进程,则替换。
非抢占式只是在就绪队列中按优先级排队。
缺点:无线阻塞或饥饿。前者为一个优先级高且运行时间长的进程一直阻塞,后者为优先级低的进程永远都得不到执行。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
操作系统进程调度是操作系统最核心的功能之一,是管理计算机系统资源的关键。Java 作为一门跨平台的编程语言,具备丰富的库和易于扩展的特性,可以很好地用于模拟操作系统进程调度。 本次课程设计旨在通过动态模拟操作系统进程调度,使学生对操作系统进程调度的原理、算法实现有更深刻的理解。课程设计的主要内容包括以下几个方面: 1. 进程调度算法的研究。该阶段需要学生对进程调度算法进行深入研究,包括常见的调度算法如 FCFS、RR、SPN、SRT 等,还可以考虑一些高级的算法,如多级反馈队列调度算法等。 2. 系统架构的设计。该阶段需要学生设计操作系统进程调度的各个模块,包括进程管理模块、进程调度模块等。此外,还需要设计用户界面,使得学生可以通过操作界面进行进程的创建、执行和回收等操作。 3. 动态模拟实现。该阶段是本课程设计的重点,需要学生使用 Java 语言编写程序实现进程调度算法的动态模拟。学生需要考虑多个进程并发执行时的问题,如进程的调度CPU 切换等。同时,学生还需要考虑系统中资源的竞争和分配问题,如内存分配、磁盘 IO 等。 4. 实验结果分析。该阶段需要学生通过对程序的运行结果进行分析,获得对进程调度算法性能的评估,以及对系统资源利用率的评估。此外,学生还可以通过对不同进程调度算法的比较,掌握进程调度算法的优缺点。 总之,本次课程设计通过动态模拟操作系统进程调度,使学生深入了解进程调度算法实现和原理,提高了学生的编程能力和调试技巧,为学生今后从事操作系统相关工作打下了坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值