进程调度模拟算法

  

一、实验目的

通过编写进程调度模拟程序,了解进程控制块(PCB)和进程队列的基本概念,体会进程调度中优先数调度算法和时间片轮转调度算法的具体实现过程。
掌握使用链表管理进程队列的方法,熟悉进程状态转移的基本流程,提高综合运用高级编程语言解决实际问题的能力。

 

二、实验要求

1.设计进程控制块 PCB 的结构,通常应包括如下信息:

进程名、进程优先数 (或轮转时间片数)、  进程已占用的 CPU 时间、进程到完成还需要 的时间、 进程的状态、  当前队列指针等。

2.

优先数调度算法程序

循环轮转调度算法程序

3.

 

 

三、实验过程

1.准备

A. 查阅资料,了解进程调度的基本概念及优先数调度、时间片轮转调度算法。

   B. 设计进程控制块(PCB)数据结构。

   C. 画出就绪队列、完成队列的数据结构示意图。

   D. 初步编写程序框架,包括主函数和各子过程。

   E. 准备测试数据,设计合理的进程NEEDTIME初值。

2.上机调试

    

A. 完成各功能模块(CREATE、INSERT、FIRSTIN、PRINT等)的编写。

B. 编写优先数调度和轮转调度两个核心调度函数。

C. 在终端调试程序,输入不同的测试数据验证正确性。

 

  1. 主要流程和源代码

主要流程

 初始化数据。

用户选择调度算法和输入进程信息

根据选择的算法进行进程调度。

显示调度状态。

询问是否继续调度,直到退出程序。

    源代码:

 

        printf("\n===== 调度开始 =====\n");

        PRINT();

#include <bits/stdc++.h>

 

#define MAX_NAME_LEN 16   // 定义进程名字的最大长度

#define TIME_SLICE   2    // 定义时间片大小为2

 

// 定义进程状态枚举

typedef enum { RUN, READY, FINISH } State;

 

// 定义进程控制块(PCB

typedef struct PCB {

    char name[MAX_NAME_LEN];  // 进程名字

    int prio;                 // 进程优先级(值越大优先级越高)

    int round;                // 时间片轮转时剩余时间(目前程序中没用到)

    int cputime;              // 进程已占用的CPU时间

    int needtime;             // 进程剩余需要的CPU时间

    State state;              // 当前进程状态

    struct PCB *next;         // 指向下一个PCB节点的指针

} PCB;

 

// 全局指针,分别指向正在运行的进程、就绪队列头尾、结束队列头

PCB *runPCB = NULL;

PCB *readyHead = NULL;

PCB *readyTail = NULL;

PCB *finishHead = NULL;

 

 

// 重置所有全局指针和链表,释放内存,准备下一轮调度

void RESET() {

    PCB *p;

    while (readyHead) {

        p = readyHead;

        readyHead = readyHead->next;

        free(p);

    }

    while (finishHead) {

        p = finishHead;

        finishHead = finishHead->next;

        free(p);

    }

    runPCB = NULL;

    readyHead = readyTail = finishHead = NULL;

}

 

// 创建一个新的PCB并加入到就绪队列尾部

PCB* CREATE(const char *name, int needtime) {

    PCB *p = (PCB*)malloc(sizeof(PCB));

    strncpy(p->name, name, MAX_NAME_LEN); // 复制名字

    p->needtime = needtime;

    p->cputime  = 0;

    p->prio     = 50 - needtime;           // 优先级初始值,需求时间越小优先级越高

    p->round    = TIME_SLICE;

    p->state    = READY;

    p->next     = NULL;

 

    if (!readyHead)

        readyHead = readyTail = p;   // 如果是第一个进程

    else {

        readyTail->next = p;         // 加到尾部

        readyTail = p;

    }

    return p;

}

 

// 按优先级插入PCB到就绪队列(高优先级在前)

void INSERT1(PCB *p) {

    p->state = READY;

    if (!readyHead || p->prio > readyHead->prio) {

        p->next = readyHead;

        readyHead = p;

        if (!readyTail) readyTail = p;

        return;

    }

    PCB *prev = readyHead;

    while (prev->next && prev->next->prio >= p->prio) {

        prev = prev->next;

    }

    p->next = prev->next;

    prev->next = p;

    if (!p->next) readyTail = p;

}

 

// 按先进先出插入PCB到就绪队列(时间片轮转用)

void INSERT2(PCB *p) {

    p->state = READY;

    p->next = NULL;

    if (!readyHead) readyHead = readyTail = p;

    else {

        readyTail->next = p;

        readyTail = p;

    }

}

 

// 将就绪队列的第一个进程取出,放到运行状态

void FIRSTIN() {

    if (!readyHead) return;

    runPCB = readyHead;

    readyHead = readyHead->next;

    if (!readyHead) readyTail = NULL;  // 如果队列空了,尾指针也置空

    runPCB->next = NULL;

    runPCB->state = RUN;

}

 

// 打印当前所有进程的状态

void PRINT() {

    printf("\nname\tcputime\tneedtime\tpriority\tstate\n");

 

    if (runPCB) {

        printf("%s\t%4d\t%4d\t\t%4d\t\tR\n",

               runPCB->name, runPCB->cputime, runPCB->needtime, runPCB->prio);

    }

    for (PCB *p = readyHead; p; p = p->next) {

        printf("%s\t%4d\t%4d\t\t%4d\t\tW\n",

               p->name, p->cputime, p->needtime, p->prio);

    }

    for (PCB *p = finishHead; p; p = p->next) {

        printf("%s\t%4d\t%4d\t\t%4d\t\tF\n",

               p->name, p->cputime, p->needtime, p->prio);

    }

    printf("-------------------------------------------------\n");

}

 

// 优先级调度算法(每次选优先级最高的进程运行)

void PRISCH() {

    while (readyHead) {

        FIRSTIN();                // 取出优先级最高的进程

        runPCB->cputime++;

        runPCB->needtime--;

        runPCB->prio--;            // 每运行一次优先级下降

        if (runPCB->needtime <= 0) {

            // 进程完成,加入到结束队列

            runPCB->state = FINISH;

            runPCB->next = NULL;

            if (!finishHead) finishHead = runPCB;

            else {

                PCB *t = finishHead;

                while (t->next) t = t->next;

                t->next = runPCB;

            }

        } else {

            INSERT1(runPCB);       // 还没完成,重新按优先级插入就绪队列

        }

        PRINT();

    }

}

 

// 时间片轮转调度算法

void ROUNDSCH() {

    while (readyHead) {

        FIRSTIN();                    // 按顺序取出进程

        runPCB->cputime += TIME_SLICE;

        runPCB->needtime -= TIME_SLICE;

        if (runPCB->needtime <= 0) {

            // 进程完成,加入结束队列

            runPCB->state = FINISH;

            runPCB->next = NULL;

            if (!finishHead) finishHead = runPCB;

            else {

                PCB *t = finishHead;

                while (t->next) t = t->next;

                t->next = runPCB;

            }

        } else {

            INSERT2(runPCB);           // 还没完成,放回就绪队列尾部

        }

        PRINT();

    }

}

 

// =================== 主程序入口 ===================

 

int main() {

    int n, i, algo;

    char name[MAX_NAME_LEN];

    int need;

    int cont = 1;  // 是否继续标志

 

    while (cont) {

        RESET();   // 每轮调度前清空上次数据

        printf("\n请选择调度算法:1-优先数算法  2-时间片轮转算法\n");

        if (scanf("%d", &algo) != 1 || (algo != 1 && algo != 2)) {

            printf("无效选择,程序退出。\n");

            break;

        }

        printf("请输入进程数目:");

        if (scanf("%d", &n) != 1 || n <= 0) {

            printf("进程数目错误,程序退出。\n");

            break;

        }

 

        // 输入每个进程的信息

        for (i = 0; i < n; i++) {

            printf("请输入第 %d 个进程的 名称 和 NEEDTIME", i+1);

            scanf("%s %d", name, &need);

            CREATE(name, need);

        }

 

        if (algo == 1) {

            PRISCH();    // 优先级调度

        } else {

            ROUNDSCH();  // 时间片轮转

        }

 

        printf("===== 调度结束 =====\n");

 

        printf("\n是否继续调度?1-继续 0-退出:");

        if (scanf("%d", &cont) != 1 || cont == 0) {

            cont = 0;

            printf("程序退出。\n");

        }

    }

 

    RESET();  // 程序结束前清理内存

    return 0;

}

 

4.遇到的主要问题和解决方法

A. 链表插入顺序出错:初期在优先数插入中未正确维护队尾指针,导致队列混乱。通过调试及时修正。

B. 进程状态切换异常:在进程完成后未正确放入完成队列,后来在调度中增加了FINISH链表处理逻辑。

  1. 内存释放问题:程序结束后增加了RESET函数,避免内存泄漏。

 

三、实验结果

优先数算法

 

 

 

 

时间片轮转算法:

 

 

 

五、实验总结

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

posted @ 2025-05-06 22:52  艾鑫4646  阅读(24)  评论(0)    收藏  举报