【操作系统】优先级调度算法(抢占式)与轮转调度算法(附代码)

优先级调度算法(抢占式)

        优先级调度算法有两种:一个是非抢占式优先级调度算法,另一个是抢占式优先级调度算法。

        优先级调度算法(抢占式)规定,在把处理机分配给优先级最高的进程并使之执行时,只要出现了另一个优先级更高的进程,调度程序就会将处理机分配给新到的优先级更高的进程。因此,在采用这种调度算法时,每当系统中出现一个新的就绪进程 i 时,系统就会将其优先级 Pi 同正在执行的进程 j 的优先级Pj进行比较,如果PiPj,则原进程;继续执行;但如果Pi>Pj.则立即停止原进程 j 的执行并进行进程切换,使新进程 i 投入执行。抢占式优先级调度算法常用于对实时性要求较高的系统中。

举个栗子:
进程到达时间运行时间优先数
P1071
P2242
P3413
P4542
  • 0-2时刻:P1到达,只有P1在运行 P1(7-2)
  • 2-4时刻:P2到达,P1优先级小于P2 ,P2开始运行 P2(4-2)
  • 4-5时刻:P3到达, P3优先级大于P2,P3开始运行 P3(1-1) P3完成
  • 5-7时刻:P4到达,P3已经运行结束,释放,P2与P4同级,P2先进入队列,P2运行,P2(4-2-2) P2完成
  • 7-11时刻:P4运行,P4(4-4) P4完成
  • 11-16时刻:P1运行 P1(7-2-5) P1完成
 附上部分代码: 找到优先级最高且未完成的进程进行调度,同时更新其状态和优先级
void cpuexe(struct pcb *q)
{
    struct pcb *t = q; // 初始化为链表的头指针,用于追踪当前最高优先级的进程。
    int max_priority = 0;
    while (q)
    { // 如果进程的状态不是 finish,将其状态设置为 ready
        if (q->process != finish)
        {
            q->process = ready;
            if (q->needtime == 0)
            {
                q->process = finish;
            }
        }
        // 更新最高优先级
        if (max_priority < q->priority && q->process != finish)
        {
            max_priority = q->priority;
            t = q;
        }
        q = q->next;
    }
    if (t->needtime != 0)
    {
        t->priority -= 3; // 将该进程的优先级减少 3,以便在下一轮调度时降低其优先级
        t->needtime--;    // 该进程已使用 1 个 CPU 时间单位
        t->process = execute;
        t->cputime++; // 记录该进程使用的 CPU 时间
    }
}

轮转调度算法

        在分时系统中,最简单也是较常用的进程调度算法是基于时间片的轮转(roundrobin,RR)调度算法。该算法采取了非常公平的处理机分配方式,即让就绪队列上的每个进程每次仅运行个时间片。如果就绪队列上有n个进程,则每个进程每次大约可获得1/n的处理机时间。

        在RR调度算法中,系统会将所有的就绪进程按FCFS策略排成一个就绪队列。系统可设置每隔一定时间(如30ms)便产生一次中断,去激活进程调度程序进行调度,把处理机分配给队首进程,并令其执行一个时间片。当它运行完后,再把处理机分配给就绪队列中新的队首进程,同样地让它也执行一个时间片。这样,就可以保证就绪队列中的所有进程,在确定的时间段内,都能获得一个时间片的处理机时间。

举个栗子:
进程到达时间运行时间
P107
P224
P341
P454

设cpu时间片为2。

  • 0-2时刻: P1到达,P1(7-2)。队列(【P1】NULL)(【】为运行进程)
  • 2-4时刻: P2到达,P2(4-2),在4时刻,P3到达,队列(【P2】 P1 -->P3)    
  • 4-5时刻:P1运行,P1(7-2-1),P4到达,队列(【P1】P3-->P2-->P4)
  • 5-6时刻:P1依然在运行,P1(7-2-2), 队列(【P1】P3-->P2-->P4)
  • 6-7时刻:P3运行,P3(1-1) P3运行完成 队列(【P3】P2-->P4-->P1)
  • 7-9时刻:P2运行,P2(4-2-2) P2运行完成 队列(【P2】P4-->P1)
  • 9-11时刻:P4运行,P4(4-2) 队列(【P4】P1)
  • 11-13时刻:P1运行,P1(7-2-2-2) 队列(【P1】P4)
  • 13-15时刻:P4运行,P4(4-2-2) P4运行完成 队列(【P4】P1)
  • 15-16时刻 :P1运行,P1(7-2-2-2-1) 运行完成 

优先级调度算法(抢占式)与轮转调度算法代码

#include <stdio.h>
#include <dos.h>
#include <stdlib.h>
#include <conio.h>
#include <io.h>

#define P_NUM 3
#define P_TIME 50
enum state
{          /*枚举类型*/
  ready,   // 就绪
  execute, // 执行
  block,   // 阻塞
  finish   // 完成
};

struct pcb
{ /*进程控制块数据结构*/
    char name[4];
    int priority;
    int cputime;  // 进程已使用的CPU时间
    int needtime; // 进程所需的CPU时间
    int count;    // 进程被调度的次数或时间片计数
    int round;    // 时间片轮转调度中的时间片使用次数
    enum state process;
    struct pcb *next;
};
struct pcb *get_process(); /*进程建立*/
struct pcb *get_process()
{
    struct pcb *q; // 用于存储新创建的进程节点的指针
    struct pcb *t; // 用于存储链表中的最后一个进程节点的指针
    struct pcb *p; // 用于存储链表头节点的指针
    int i = 0;
    printf("input name and needtime, please input 3 processes\n");
    while (i < P_NUM)
    {
        // 创建新的进程节点
        q = (struct pcb *)malloc(sizeof(struct pcb));
        scanf("%s", &(q->name));
        scanf("%d", &(q->needtime));
        q->cputime = 0;
        q->priority = P_TIME - q->needtime; // 通过剩余时间初始化优先级
        q->process = ready;                 // 初始状态为 "就绪" 状态
        q->next = NULL;                     // 新建节点的 "next" 设为 NULL
        // 将新创建的节点插入到进程链表中
        if (i == 0)
        { // 第一个进程,初始化链表头指针 p 和 t
            p = q;
            t = q;
        }
        else
        {
            t->next = q;
            t = q;
        }
        i++;
    } /*while*/
    // 结构类似于q1(p)-->q2-->q3(t)
    return p;
}
// 遍历链表中的 PCB,输出每个进程的详细信息
void display(struct pcb *p)
{
    printf("name    cputime    needtime    priority    state\n");
    while (p)
    {
        printf("%s", p->name);
        printf("        ");
        printf("%d", p->cputime);
        printf("        ");
        printf("%d", p->needtime);
        printf("        ");
        printf("%d", p->priority);
        printf("        ");
        switch (p->process)
        {
        case ready:
            printf("ready\n");
            break;
        case execute:
            printf("execute\n");
            break;
        case block:
            printf("block\n");
            break;
        case finish:
            printf("finish\n");
            break;
        }
        p = p->next;
    }
}

int process_finish(struct pcb *q)
{ /*进程是否结束,当还有进程没有结束时返回0*/
    int bl = 1;
    while (bl && q)
    {
        bl = bl && q->needtime == 0;
        q = q->next;
    }
    return bl;
}

void cpuexe(struct pcb *q)
{
    struct pcb *t = q; // 初始化为链表的头指针,用于追踪当前最高优先级的进程。
    int max_priority = 0;
    while (q)
    { // 如果进程的状态不是 finish,将其状态设置为 ready
        if (q->process != finish)
        {
            q->process = ready;
            if (q->needtime == 0)
            {
                q->process = finish;
            }
        }
        // 更新最高优先级
        if (max_priority < q->priority && q->process != finish)
        {
            max_priority = q->priority;
            t = q;
        }
        q = q->next;
    }
    if (t->needtime != 0)
    {
        t->priority -= 3; // 将该进程的优先级减少 3,以便在下一轮调度时降低其优先级
        t->needtime--;    // 该进程已使用 1 个 CPU 时间单位
        t->process = execute;
        t->cputime++; // 记录该进程使用的 CPU 时间
    }
}

void priority_cal()
{ /*优先数调度*/
    struct pcb *p;
    int cpu = 0;       // 记录 CPU 执行的时间
    p = get_process(); // p是头指针
    while (!process_finish(p))
    {
        cpu++;
        printf("cputime:%d\n", cpu);
        cpuexe(p);  // 运行
        display(p); // 输出每个进程的详细信息
        sleep(5);
    }
    printf("All processes have finished,press any key to exit");
    getch();
}

void display_menu()
{
    printf("CHOOSE THE ALGORITHM:\n");
    printf("1 PRIORITY\n");
    printf("2 ROUNDROBIN\n");
    printf("3 EXIT\n");
}
struct pcb *get_process_round()
{ /*轮转进程建立 头进尾插*/
    struct pcb *q;
    struct pcb *t;
    struct pcb *p;
    int i = 0;
    printf("input name and time,please input 3 processes\n");

    while (i < P_NUM)
    {
        q = (struct pcb *)malloc(sizeof(struct pcb));
        scanf("%s", &(q->name));
        scanf("%d", &(q->needtime));
        q->cputime = 0;     // 初始化cpu使用时间
        q->round = 0;       // 初始化时间片使用次数
        q->count = 0;       // 记录每个进程被调度次数的变量
        q->process = ready; // 就绪
        q->next = NULL;     // 下一节点为NULL
        if (i == 0)
        { // 第一个进程,初始化链表头指针 p 和 t
            p = q;
            t = q;
        }
        else
        {
            t->next = q;
            t = q;
        }
        i++;
    } /*while*/
    // q1(p)-->q2-->q3-->q4(t)
    return p;
}

void cpu_round(struct pcb *q) /*处理机轮转*/
{
    // 时间片为2
    q->cputime += 2;
    q->needtime -= 2;
    if (q->needtime < 0)
    // 解决needtime为1的问题
    {
        q->needtime = 0;
    }
    q->count++; // 次数
    q->round++;
    q->process = execute; // 执行
}

struct pcb *get_next(struct pcb *k, struct pcb *head)
{ /*返回没有结束的进程*/
    struct pcb *t;
    t = k;
    do
    {
        t = t->next;
    } while (t && t->process == finish);
    if (t == NULL) // 如果到达链表末尾 从头开始 遍历到找到未完成的进程
    {
        t = head;
        while (t->next != k && t->process == finish)
        {
            t = t->next;
        }
    }
    return t;
}

void set_state(struct pcb *p)
{ // 更新链表中每个PCB的状态
    while (p)
    {
        if (p->needtime == 0)
        {
            p->process = finish;
        }
        if (p->process == execute)
        {
            p->process = ready; // 如果进程正在执行,将状态设置为 'ready'
        }
        p = p->next;
    }
}

void display_round(struct pcb *p)
{ // 显示当前各个进程的状态和资源使用情况
    printf("NAME  CPUTIME  NEEDTIME  COUNT  ROUND  STATE\n");
    while (p)
    {
        printf("%s", p->name);
        printf("        ");
        printf("%d", p->cputime);
        printf("        ");
        printf("%d", p->needtime);
        printf("        ");
        printf("%d", p->count);
        printf("        ");
        printf("%d", p->round);
        printf("        ");
        switch (p->process)
        {
        case ready:
            printf("ready\n");
            break;
        case execute:
            printf("execute\n");
            break;
        case finish:
            printf("finish\n");
            break;
        }
        p = p->next;
    }
}

void round_cal()
{ /*循环轮转调度*/
    struct pcb *p;
    struct pcb *r;
    int cpu = 0; // 累计执行时间
    // 轮转进程建立
    p = get_process_round();
    r = p;
    while (!process_finish(p)) // 判断进程是否结束
    {
        cpu += 2;
        cpu_round(r);       // 处理当前的轮转
        r = get_next(r, p); // 返回没有结束的进程
        printf("cpu %d\n", cpu);
        display_round(p); // 显示当前各个进程的状态和资源使用情况
        set_state(p);     // 更新链表中每一个PCB的状态
        sleep(5);
    }
    printf("All processes have finished,press any key to exit");
    getch();
}

/* 主程序 */
void main()
{
    int user_input;
    display_menu();
    scanf("%d", &user_input);
    switch (user_input)
    {
    case 1:
        priority_cal();
        break;
    case 2:
        round_cal();
        break;
    case 3:
        break;
    default:
        display_menu();
        scanf("%d", &user_input);
        break;
    }
}

出现这个错误的原因是在导入seaborn包时,无法从typing模块中导入名为'Protocol'的对象。 解决这个问题的方法有以下几种: 1. 检查你的Python版本是否符合seaborn包的要求,如果不符合,尝试更新Python版本。 2. 检查你的环境中是否安装了typing_extensions包,如果没有安装,可以使用以下命令安装:pip install typing_extensions。 3. 如果你使用的是Python 3.8版本以下的版本,你可以尝试使用typing_extensions包来代替typing模块来解决该问题。 4. 检查你的代码是否正确导入了seaborn包,并且没有其他导入错误。 5. 如果以上方法都无法解决问题,可以尝试在你的代码中使用其他的可替代包或者更新seaborn包的版本来解决该问题。 总结: 出现ImportError: cannot import name 'Protocol' from 'typing'错误的原因可能是由于Python版本不兼容、缺少typing_extensions包或者导入错误等原因造成的。可以根据具体情况尝试上述方法来解决该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ImportError: cannot import name ‘Literal‘ from ‘typing‘ (D:\Anaconda\envs\tensorflow\lib\typing....](https://blog.youkuaiyun.com/yuhaix/article/details/124528628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值