操作系统实验一:CPU调度(优先级调度、时间片轮转调度)

实验《CPU Scheduling》

实验学时:  4     实验地点: 第二综合楼204  实验日期: 2022/10/25 

一、实验目的

多道系统中,当就绪进程数大于处理机数时,须按照某种策略决定哪些进程优先占用处理机。本实验模拟实现处理机调度,加深了解处理机调度的工作过程。

  • 实验内容

    选择一个调度算法,实现处理机调度。

1、设计一个按优先权调度算法实现处理机调度的程序;

      2、设计按时间片轮转实现处理机调度的程序。

三、实验方法

1)构建PCB,内容涵盖:

     进程名/PID;

     要求运行时间(单位时间);

     优先权;

     到达时间:

     状态:

     PCB指针;

  1. 设计两种调度算法:抢占式优先级调度,时间片轮转法调度;
  2. 设计随机创建进程,挂起,解挂,切换调度算法功能;
  3. 使用工具为QT,采用图形界面,动态展示调度过程当中各进程及队列变化。

四、实验过程

1、需求分析:

1)可自行编辑创建进程,也可随机创建进程,后备队列中按照到达时间排序,选择最多六个进程进入就绪队列,优先级调度算法时就绪队列中按照优先级进行排序;

2)按照不同的算法进行不同的调度方法:抢占式优先级调度:从就绪队列选择优先级最高的进程进行运行,每运行一个时间片后,优先级减一,运行时间减一,当运行时间为0时,进程运行完成;时间片轮转法调度:按照先到先运行法则,每运行一个时间片后退出运行,换另外一个进程运行,运行时间为0,则进程运行完成;

3)使用QT完成图形界面;

4)设置挂起和解挂功能;

5)可动态增加进程;

6)如果内存中进程数少于规定道数,可自动从后备队列通过作业调度选择一作业进入,作业调度算法可自行选择;

7)被挂起进程入挂起队列,设置解挂功能用于将指定挂起进程解挂并入就绪队列;

8)每次调度后,显示各进程状态,采用进度条形式展现。

2、概要设计:

1)进行UI设计:添加进程、随机添加进程、backup队列、ready队列、running队列、suspend队列、进程信息显示框;

2)设置添加创建进程按钮,随机创建进程按钮,用户可输入进程名称,运行时间,到达时间,优先级从而添加到backup队列中,或者直接随机创建多个进程添加到backup队列中;

3)设置挂起和解挂按钮,用户选中ready队列或running队列中进程,点击挂起即可将该进程放入suspend队列中,选中挂起队列中的进程,点击解挂即可将该进程放入ready队列中;4)设置运行按钮,程序一直处于运行状态,直到所有进程完成或者点击暂停按钮;

5)设置暂停按钮,将处于一直运行的程序暂停;

6)设置信息显示框,显示所有信息的各个状态变化,运行时长等信息;

7)设置算法调度按钮,不同的按钮代表不同的算法;

8)自定义item加入QTableWidget中显示数据,设置进度条,展示进程完成百分比;

9)优化界面将界面做的更加美观

3、详细设计:

1)图形界面使用QTableWidget、QLable、QPushButton、QProgerssBar、QTextLine、QText完成图形化设计;

2)考虑算法思路,定义PCB类,声明必要属性,以及get&set方法;

3)设置运行按钮,使用QTimer计时器,程序每秒运行一次;

4)设置挂起功能,用户点击ready队列中的进程,获得该进程的信息,点击挂起即可将该进程挂起,信息转移到suspend队列中;

5)设置解挂功能,用户点击suspend队列种的进程,获得该进程的信息,点击解挂即可将该进程放入ready队列,再根据算法进行排序。

五、实验代码

1)PCB类:

class PCB

{

private:

    QString PID;

    QString status;

    int priority;

    int runtime;

    int max_runtime;

    PCB *pcb;

public:

    PCB();

    PCB(QString PID,QString status,int priority,int runtime);

    void setRuntime(int value);

    void delRuntime(int value);//进程运行时间减少value

    void setStatus(QString value);

    void setPID(QString value);

    void setMaxRuntime(int value);//设置进程需要的总运行时间

    void setPriority(int value);

    void delPriority(int value);//进程优先级权值减少value

    void addPriority(int value);//进程优先级权值增加value

    void setDefaultPCB();

    QString getPID() const;

    int getRuntime() const;

    int getMaxRuntime() const;

    QString getStatus() const;

    int getPriority() const;

};

  1. 每秒更新一次的优先级调度算法

void Widget::refreshProcs_SJF()

{

    ui->lab_CPUScheInfo->setText("调度中...");

    //取运行进程的优先级、就绪队列第一个进程的优先级

    priority_run = runningProcs->getPriority();

    priority_ready1st = ready[0].getPriority();

    //如果内存中进程数不超过6且后备队列第一条数据不为空,则自动从后备队列中添加进程

    if(backup[0].getPriority()!=0)

    {

        for(;processNum<NUM_OF_PROCESS;)

        {

            if(backup[0].getPriority()==0)

            {

                break;

            }

            firstOfBackToReady();

            delFirstOfBackup();

            backupToUi();

        }

    }

    //进程抢占:当就绪队列第一条数据的优先级大于运行进程时,注意顺序不要搞错

    if(priority_ready1st > priority_run)

    {

        ui->lab_CPUScheInfo->setText("发生抢占");

        //被抢占的进程重新加入就绪队列

        runningToReady();

        //就绪队列第一个进程进入运行队列

        firstOfReadyToRunningUi();

        runningToUi();

        //在就绪队列中删除第一个进程

        delFirstOfReady();

        readyToUi();

        //对就绪队列进行排序,更新界面

        bubbleSort(ready);

        readyToUi();

    }

    //运行中的进程优先级-1,运行时间-1,运行时间==0时修改状态,输出在进程信息TableWidget

    if(runningProcs->getPriority()!=0 && runningProcs->getRuntime()-1!=0)

    {

        runningProcs->delPriority(1);

        runningProcs->delRuntime(1);

        //刷新ui界面上的运行调度ui界面

        runningToUi();

    } else {

        runningProcs->setStatus("终止");

        //在进程调度信息处输出终止进程的信息

        finishToInfo();

        //就绪队列第一个进程加入RunningProcs中

        firstOfReadyToRunningUi();

        //在就绪队列中删除该条信息

        delFirstOfReady();

        //给就绪进程数组重新排序

        bubbleSort(ready);

        //刷新就绪列表ui界面

        readyToUi();

    }

    //就绪队列中等待的进程优先级+1

    for(int i = 0;i<NUM_OF_PROCESS&&ready[i].getPriority()!=0;i++)

    {

        ready[i].addPriority(1);

    }

    //刷新就绪列表ui界面

    readyToUi();

    //刷新挂起列表ui界面

    suspendToUi();

}

  1. 每时间片更新一次的时间片轮转法

void Widget::refreshProcs_RR()

{

    ui->lab_CPUScheInfo->setText("调度中...");

    //如果内存中进程数不超过6且后备队列第一条数据不为空,则自动从后备队列中添加进程

    if(backup[0].getPriority()!=0)

    {

        for(;processNum<NUM_OF_PROCESS;)

        {

            if(backup[0].getPriority()==0)

            {

                break;

            }

            firstOfBackToReady();

            delFirstOfBackup();

            backupToUi();

            readyToUi();

        }

    }

    //每隔1s调用一次refreshProcs_RR函数,运行中进程运行时间一次-1,时间片为3

    if(sliceTime<TIMESLICE)

    {

        if(runningProcs->getRuntime()-1==0)//进程终止后

        {

            runningProcs->setStatus("终止");

            //在进程调度信息处输出终止进程的信息

            finishToInfo();

            //就绪队列第一个进程加入RunningProcs中

            firstOfReadyToRunningUi();

            //在就绪队列中删除第一条信息

            delFirstOfReady();

            //刷新就绪列表ui界面

            readyToUi();

        }

        sliceTime++;

        runningProcs->delRuntime(1);

        //刷新ui界面上的运行调度ui界面

        runningToUi();

    } else {//一次时间片之后,进程仍未结束,则将该进程重新加入到就绪队列的最后一条

        //将运行的进程加入到就绪度列最后一条

        runningToReady();

        //就绪队列第一条进程进入运行列表

        firstOfReadyToRunningUi();

        //删除就绪队列第一条数据

        delFirstOfReady();

        //刷新就绪队列ui界面

        readyToUi();

        sliceTime = 0;

    }

}

4)进程挂起

void Widget::receiveRunningToSuspend(QString PID)

{

    qDebug()<<"receiveRunningToSuspend...";

    //将运行进程加入挂起队列

    workToSuspend(*runningProcs);

    //更新挂起队列的ui界面

    suspendToUi();

    //将就绪队列第一条数据加入到运行列表

    firstOfReadyToRunningUi();

    //删除就绪队列第一条数据

    delFirstOfReady();

    //刷新就绪队列界面

    readyToUi();

}

5)进程解挂

void Widget::receiveSuspendToReady(QString PID)

{

    qDebug()<<"被解挂的进程PID:"+PID;

    for(int i = 0;i<NUM_OF_PROCESS;i++)

    {

        if(suspend[i].getPID() == PID)

        {

            qDebug()<<"receiveSuspendToReady...";

            //将被解挂的进程加入就绪队列

            suspendToReady(suspend[i]);

            //给就绪数组排序

            bubbleSort(ready);

            //更新就绪队列的ui界面

            readyToUi();

            //删除挂起队列中的该进程

            delOneOfSuspend(PID);

            //更新挂起队列的ui界面

            suspendToUi();

            break;

        }

    }

}

  • 实验结论

添加作业

选择调度算法

 

  1. 优先级调度  

开始调度

挂起、解挂进程

2)时间片轮转法

开始调度

七、实验小结

1)UI界面:花了有一段时间设计界面,综合考虑后自定义了进程item,与QStandardItem绑定后显示在QTableWidget中,加入了表单、进度条和按钮,使数据显示更加优美;

2)QTimer:设置了一秒更新一次的时间片,也可以让用户自己设置时间片,项目还不够完整,可以继续改进;

3)信号与槽:不同类之间的通信采用了信号与槽的connect方法,方便item、添加作业页面和选择调度算法页面与主页面的消息传递,Qt这一点很方便;

4)具体算法:把常用的方法都封装起来,便于后期对项目进行优化、升级时的维护,也便于撰写其他调度算法;

5)PCB实现:指针应用还是不够熟练,不能清晰得运用指针指向下一个进程的PCB,导致整个程序过于依赖内存,但考虑到这是轻量级项目,还能够原谅,但仍需改进。

  • 4
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,我明白了。对于这个问题,我可以提供一些思路。 进程调度是操作系统的一个重要功能,它负责决定哪些进程可以占用 CPU,以及在何时执行。在 Linux 中,进程调度是由调度器(scheduler)来实现的。Linux 采用了多种调度策略来满足不同的需求,其中包括时间片轮转调度和静态优先级调度时间片轮转调度是一种常见的调度策略,它基于每个进程被分配一定的时间片(通常为几十毫秒),然后按照时间片的顺序轮流执行。当一个进程的时间片用完时,调度器会将 CPU 分配给下一个进程,并将当前进程放回就绪队列的末尾。这种调度策略可以确保所有进程都能够获得一定的 CPU 时间,避免了某些进程长时间占用 CPU 的情况。 静态优先级调度是另一种调度策略,它基于为每个进程分配一个固定的优先级值,并按照优先级的顺序执行。在 Linux 中,进程的优先级值范围是 0 到 139,其中 0 表示最高优先级,139 表示最低优先级调度器会根据进程的优先级来决定哪个进程应该先执行。这种调度策略适合于对实时性要求比较高的应用程序,但可能会导致优先级较低的进程长时间得不到执行。 在 Linux 中,可以通过修改调度器的行为来实现不同的调度策略。例如,可以使用 CFS(Completely Fair Scheduler)来实现时间片轮转调度,或者使用 O(1) 调度器来实现静态优先级调度。此外,还可以使用调度策略和优先级来控制进程的调度行为,例如使用 nice 命令来整进程的优先级值。 希望这些信息能够帮助你理解如何在 Linux 中设计一个进程调度系统,包括时间片轮转调度和静态优先级调度。如果你有任何疑问或者需要更详细的信息,请随时提出。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值