Geekos-project3 项目3:进程调度算法与信号量功能

文章详细介绍了在GeekOS操作系统中实现进程调度算法,包括时间片轮转和多级反馈队列,以及如何使用信号量进行进程同步。项目要求实现特定的系统调用,如设置调度策略、获取时间以及信号量操作。文中还分析了调度算法的原理,文件结构和主要函数的功能,并展示了测试结果。
摘要由CSDN通过智能技术生成

2.4 Project3

2.4.1项目设计目的

        研究进程调度算法,掌握用信号量实现进程间同步的方法。为GeekOS扩充进程调度算法——基于时间片轮转的进程多级反馈调度算法,并能用信号量实现进程协作。

2.4.2项目设计要求

(1)实现src/geekos/syscall.c文件中的Sys_SetSchedulingPolicy系统调用,它的功能是设置系统采用的何种进程调度策略;

(2)实现src/geekos/syscall.c文件中的Sys_GetTimeOfDay系统调用,它的功能是获取全局变量g_numTicks的值;

(3)实现函数Change_Scheduling_Policy(),具体实现不同调度算法的转换。

(4)实现syscall.c中信号量有关的四个系统调用:sys_createsemaphore()、sys_P()、sys_V()和sys_destroysemaphore()。

2.4.3原理分析

(1)关于时间片轮转的进程多级反馈调度算法的原理:

        首先,优先级随反馈队列级数的增加而下降,即:数字越小的反馈级队列,其执行的优先级最高;时间片大小随反馈队列级数的增加而增大,即:数字越大的反馈级队列,其拥有的时间片越大。

1时间片轮转的多级反馈调节

(2)在该项目3中的时间片轮转与多级反馈队列相互间的转换

2多级反馈队列调节与时间片轮转的相互转换

2.4.4主要文件分析

(1)Synch.c文件:执行信号量代码,确保在进程切换时,只执行一个进程。

        在原有函数基础上增加了部分函数,其重要的函数有Create_Semaphore()函数,该函数作用为创建一个新的信号量,首先判断是否出现错误,包括同名或者不存在的错误,而后初始化信号量并设置信号量相关值,将新创建的信号量加入到信号量列表中;

        P()函数,为获取进程信号量,先检查是否存在错误,无问题后,若减去1后信号量的值小于0,那么就把当前线程放入这个信号量的等待队列;

        V()函数,为释放进程信号量,先检查是否存在错误,无问题后,若加上1后信号量的值小于或等于0,则要把该信号量里等待队列上的一个线程唤醒;

        Destroy_Semaphore()函数,先检查是否存在错误,无问题后,把该线程从这个信号量的注册的线程数组中删除,并把注册的线程数量减去1,这个信号量的注册线程为0了,则把这个信号量从信号量链表中删除,并释放它的内存,并唤醒该信号量等待队列中所有线程。

3信号量有关操作

(2)syscall.c文件:是执行时间片轮转和多级反馈队列调度策略的核心文件。

        首先,最重要的Interrupt_State结构体,位于int.h头文件中,其定义了很多变量,其中最重要的变量是ecx(时间片)和ebx(调度策略)。

        而函数Sys_SetSchedulingPolicy(),其功能是设置系统采用何种进程调度策略(若state->ebx为0则采取时间片轮转调度,为1则是四级反馈调度);函数Sys_GetTimeOfDay()为直接返回全局变量g_numTicks值(在timer.c和time.h有定义),是时间片大小。

        函数Sys_CreateSemaphore()是调用Synch.c文件文件中的Create_Semaphore()函数,来创建一个信号量,其中,类似的,Sys_P()函数、Sys_V()函数、Sys_DestroySemaphore()函数。

(3)Kthread.c文件:该文件占有着极其重要的作用,运用到了项目二的用户级线程,而在本项目中,主要作用为对进程调度的初始化、更变、压入等待队列、压入就绪队列等有关进程调度方面的实现。

        首先了解Kernel_Thread结构体(在kthread.h头文件中),其记录着进程状态及有关信息的数据结构;函数Init_Scheduler()是系统调度进程初始化,在调度初始化时,会产生三个主线程,mainThread、idle和Reaper,而mainThread是当前执行的线程(进程),idle相当于空闲线程(进程),Idle进程为保证准备运行队列中有可调度的进程,即当无运行到进程时,cpu将执行idle进程,而Reaper负责消亡进程的善后工作,如释放消亡进程占用的资源,内存、堆栈等。

        Make_Runnable()函数目的是将线程压入就绪队列,即将当前运行进程放入准备运行进程队列,在时钟中断处理Time_Interrupt_Handle函数之后,通过编译程序Handle_Interrupt(Handle_Interrupt)检查g_needReschedule是否更改为true,若是则调用Make_Runnable该函数,其中,s_runQueue:准备运行进程队列。

        Chang_Scheduling_Policy()函数是改变系统调度到策略,即实现不同调度算法到转换,从时间片轮转调度到多级反馈调度,从最后一个线程队列(此处为 Q3)开始将其中的所有线程依次移动到前一个队列,直到所有线程都移动到 Q0 队列;若从多级反馈调度到时间片轮转调度则相反。而该处也是输出所采取的调度策略以及时间片大小之处。

        Get_Next_Runnable()函数,找到下一个进程(优先级最高到进程)进行执行,实现进程调度算法,当然,执行完该程序后,需返回Handle_Interrupt将g_needReschedule返回为false,并切换到新进程运行。其查找策略为从最高层队列依次向下查找本层队列中最靠近队首的线程,如果找到则不再向下继续查找。

4系统进程调度

(4)timer.c文件:有关时钟中断操作的文件存在。

        其中重要的函数当为Timer_Interrupt_Handler()时钟中断函数,g_currentThread变量代表着当前线程的存在,g_currentThread->numTicks代表着时间片大小,每次中断变量加1;若g_currentThread->numTicks大于或等于规定到时间片g_Quantum,则表示g_needReschedule设为true,表示时间片已超时,应调入新进程运行,这时,系统调用Make_Runnable函数将当前正在运行到进程放入准备运行到进程队列中,即完成系统进程调度操作。

(5)semtest.c文件:存在于user文件夹下,是对输入操作的选择。

        其中,“rr”代表时间片轮转,“mlf”代表多级反馈调度。若输入“rr”,则调度策略变量policy为0;若输入“mlf”,则调度策略变量policy为1。

        利用三个进程来演示进程调度算法,分别为文件sched1、sched2、sched3。例如,文件sched1运用的也是一直循环操作,利用“for(j=0;j<20000;j++)”来停顿,以便系统可以变换调度策略来改变进程不一样的执行操作,其它两个文件也是类似的操作。

        因此,可以根据输出的文件顺序(三个文件分别只输出1、2、3)来判断是否执行了进程调度策略的更改。

2.4.5运行输出分析结果

(1)测试调度算法

schedtest rr 1   时间片

schedtest mlf 1  多级反馈

3测试的调度算法运行结果

4测试的时间片轮转的运行结果

        在schedtest测试用例中,时间片轮转算法(RR)和多级反馈调度算法(MLF),所设时间片一样,皆为1时,此时由于多级反馈调度算法(MLF)进行了优先级的调整,切换进程的时间也不同,所输出的时间可能不同。

        时间片轮转算法(RR)中,所设时间片不一样,分别为1、10时,输出的结果1、2、3大致相同。

(2)测试负载

workload rr 1

workload mlf 1

用Long、Ping两用户进程计算运行时间

5测试负载的运行结果

        利用workload来测试用户进程的调度时间,由于多级反馈调度算法(MLF)并不像所了解的那种时间片逐步增加,而是一样的时间片大小,且会进行优先级的调整,故时间片轮转算法(RR)稍弱于多级反馈调度算法(MLF)。

(3)用semtest、semtest1、semtest2三个用户进程对信号量进行功能测试

semtest

semtest1

semtest2

6测试用户进程对信号量进行功能测试-semtest

7测试用户进程对信号量进行功能测试-semtest1

8测试用户进程对信号量进行功能测试-semtest2

        由实验结果可知,semtest测试时,其创建、P、V以及销毁操作顺利完成;semtest1测试时,其出现了等待信息,属于produced生产者和consumed消费者的同步操作;semtest2测试时,信号量ID出现错误,其针对错误信号量进行执行,毫无疑问,系统关于pv信号量的执行代码对于错误信号量会发出错误提示,以致其无法正确的执行代码,故而,所写的有关信号量的相关代码是为正确的。

2.4.6解决作业问题

1GeekOS系统原始的线程调度算法是什么?

GeekOS系统原始的线程调度算法是先来先服务算法(FCFS)。

2)在GeekOS系统中,如何实现多级反馈队列调度算法?

        在GeekOS系统中,进程就绪队列分为4级,按照优先级从高到低排列分别为Q0、Q1、Q2和Q3队列;新创建的进程会被置入最高优先级的就绪队列Q0;每当一个进程运行完一个时间片长度之后,它就会被置入比之前低一级的就绪队列,直到到达优先级最低的队列Q3。

        此外,如果进程被阻塞,则队列优先级就会提升等级,直到被阻塞三次后达到最高优先级队列Q0,系统中的空闲进程Idle会始终放在优先级最低的队列Q3的尾部,以便系统中没有其他可调度进程时就运行它。

注意:该系统的多级反馈调度队列算法中的时间片保持一致,并不会随优先队列的改变而变化。

3)在GeekOS系统中,如何创建一个信号量?

        在GeekOS系统中,利用syscall.c文件下的Sys_CreateSemaphore()函数定义创建信号量的内容,最后利用synch.c文件下的Create_Semaphore()函数创建一个信号量。

        其中,Sys_CreateSemaphore()函数定义着信号量名字符串所在用户空间地址、信号量名长度以及信号量初始值,若如果传入参数不正确则返回错误;从用户空间拷贝信号量名字符串到内核空间,并判断信号量名的合法性(中间是否含有'\0'字符)。Create_Semaphore()函数则是首先检查请求创建的这个信号量的名字是否存在,如果存在,那么就把这个线程加入到这个信号量所注册的线程链表上;如果不存在,则分配内存给新的信号量,清空它的线程队列,把当前的这个线程加入到它的线程队列中,设置注册线程数量为0,初始化信号量的名字,值和信号量的ID,并把这个信号量添加到信号量链表上,最后返回信号量的ID。

4)在GeekOS系统中,如何通过信号量来实现进程同步?

        在测试进程调度时,在文件schedtest.c下,具有函数wait函数(wait函数的含义:对wait()的调用会阻止调用进程,直到它的一个子进程退出或收到信号为止。子进程终止后,父进程在wait系统调用指令后继续执行);故而控制信号量同步操作;而在synch.c文件下原有代码中有Mutex_Wait函数,该函数的意义是对互斥量进行锁定,使其无法异步读取或者避免产生不一致的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值