陈香兰操作系统实验三

本文详细介绍了通过实现多级队列二级调度实验来深化对进程和线程调度理解的过程。实验包括任务参数设定、调度算法实现及测试用例分析,通过设计任务管理、调度初始化、中断处理等关键步骤,展现了优先级、执行时长和时间片轮转的调度效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多级队列二级调度

实验目的:

通过实现任务调度,加深对进程,线程调度的理解

实验内容:

  1. 实现任务参数设定原语setTskPara(),getTskPara()等,以支持设定优先级Priority/执行时长ExeTime/到达时间ArriveTime等参数
  2. 修改任务创建原语,以设定任务参数
  3. 实现SJF/优先级/时间片轮转/多级队列调度算法
  4. 修改osStart原语,以增加相关功能的初始化
  5. 测试用例[老师提供userApp目录]:创建一组运行时间较长的任务,运行过程中输出相关信息(要求能展现优先级/时长/时间片轮转的效果)。

具体过程:

设计:

graph A{
    a[label=osStart];
    a1[label=TaskmanagerInit];
    a2[label=InitTsk];
    a3[label=schedulerinit];
    a4[label=enable_interrupt]
    a5[label=disable_interrupt]
    a6[label=init_time_interrupt]
    a--a6;a--a1;a--a3;a--a2;
    b1[label=create_but_not_start_idletsk]
    b2[label=createtsk1];
    b3[label=createtsk2];
    b4[label=createtsk3];
    b5[label=createtsk4];
    b6[label=tskend];
    a1--b1;a2--{b2;b3;b4;b5;b6};
    c1[label=enqueue];
    c2[label=tskstart]
    {b2;b3;b4;b5}--c2--c1;
    d1[label=tick];
    d2[label=sheduler_tick];
    d3[label=next];
    d4[label=content_switch];
    d5[label=CTX_SW];
    d6[label=destroy];
    a4--d1[label=开了中断];
    d1--d2;d2--d3[label=用完时间片];d2--d6[label=当前任务运行完了];d6--d3[label=当前任务出队列并释放空间后找下一个];d3--d4[label=下一个任务不是当前任务];
    d4--d5;
}
//主要的数据结构
typedef struct tskPara{
	unsigned int priority;//优先级
	unsigned int exeTime;//要运行的时间
	unsigned int arrTime;//到达时间
	unsigned int schedPolicy;//调度策略
} tskPara;
//作为任务的参数
typedef struct myTCB {
	unsigned long state;  //任务状态 0表示处于rdy
	int tcbIndex;//任务号
	struct myTCB * next;//单向链表的连接指针
	unsigned long* stkTop;//任务的运行栈顶
	unsigned long stack[STACK_SIZE]; //任务的运行栈
	tskPara para; 	//任务的参数
} myTCB;
//任务结构
myTCB tcbPool[TASK_NUM];//任务池用于分配
myTCB * currentTsk;//指向当前任务的指针
myTCB * firstFreeTsk;//第一个可供分配的空闲任务空间
#define MAX_USER_PRIORITY_NUM 20
//用户可定义的最大优先级
#define MAX_PRIORITY_NUM MAX_USER_PRIORITY_NUM+1
//系统可定义的最大优先级
int ms=0;//系统运行的ms数
int defaultRtSlice=100;//默认的实时任务的时间片
int defaultSlice=100;//默认非实时任务的时间片
int runtime=0;当前时间片内已运行的时间;

#define SCHED_UNDEF   0x0000
#define SCHED_FCFS    0x0010
#define SCHED_SJF     0x0020
#define SCHED_PRIO    0x0030
#define SCHED_RR      0x0040
#define SCHED_RT_FCFS 0x0050
#define SCHED_RT_RR   0x0060
#define SCHED_IDLE    0x0070
//几种调度策略
struct scheduler {
    unsigned int type;  //类型

    myTCB* (*nextTsk_func)(void);//找下一个任务
    void (*enqueueTsk_func)(myTCB *tsk);//入队列
    void (*dequeueTsk_func)(myTCB *tsk);//出队列
    void (*tick_hook)(void);//tick时调用
}SysScheduler;
//系统的调度器
struct TskQueue {
	myTCB *head;//头指针
	myTCB *tail;//尾指针
	myTCB *idletsk;//idle任务指针
}TskQueue;
//任务队列

原语

//原语
void osStart(void);
//用于系统初始化(时钟初始化,调度器初始化,任务控制的初始化)和转入多任务运行
void TaskManagerInit(void);
//任务控制的初始化(初始化任务池,创建idle任务在空闲时运行,创建init作为下一个要运行的任务,初始化空闲任务空间分配)
void initTskPara(tskPara *buffer);
//对传来的tskPara进行初始化
void context_switch(myTCB *prevTsk, myTCB *nextTsk);
//任务切换
void destroyTsk(int takIndex);
//释放任务空间回到任务池中等待分配
void setSysSchedulerPara(unsigned int who, unsigned int para);
//设定默认的实时或非实时的任务的时间片
void getSysSchedulerPara(unsigned int who, unsigned int *para);
//用para返回要查看的参数
void setSysScheduler(unsigned int what);
//设置系统调度器的参数
unsigned int getSysScheduler(void);
//查看系统调度器的参数
void setTskPara(unsigned int option, unsigned int value, tskPara *buffer);
//设置传来的buffer指向的Para
void scheduler_tick(void);
//tick时进行调度,时间片运行完了或当前任务已经运行结束了要调next()函数
void schedulerInit();
//对系统调度器进行初始化
void getTskPara(int taskID, tskPara *buffer);
//获得相应ID的任务的tskPara
int createTsk(void (*tskBody)(void), tskPara *para);
//创建一个任务,进行栈的初始化,更新下一个可分配的空间
void stack_init(unsigned long** stk,void (*task)(void));//栈的初始化
void tskStart(myTCB *tsk);//启动一个任务,设状态,入队列
void dequeueTsk(myTCB *tsk);//任务出队列
void enqueueTsk(myTCB *tsk);//入队列
myTCB * nextTsk(void);//返回任务队列中已经到达且变相优先度最小的,队列空返回idle
unsigned flag(tskPara para);//将非实时任务的优先度加一个最大优先级(MAX_PRIORITY_NUM)从而实现变相有限度
int TskQueueIsEmpty(void);//判断任务队列是否为空
void TskQueueInit(myTCB* idleTsk);//任务队列初始化,头尾节点赋空

测试:
我先只写了支持的SCHED_RT_FCFS和SCHED_RT_RR的,时间片都给100个tick(1000ms),init 0ms到,优先度0,运行100ms,RT_FCFS,tsk1 6ms到,优先度12,运行1200ms,RT_RR,tsk2 150ms到,优先度8,运行80ms,RT_RR,tsk3 550ms到,优先度8,运行50ms,RT_RR,tsk4 550ms到,优先度8,运行30ms,RT_RR
使用了

  qemu-system-i386 -s -S -fda ./output/a_boot2C.img

gdb ./output/myOS.elf
(gdb)>target remote localhost:1234

qemu-system-i386 -s是在本地TCP:1234端口接受调试,-S是启动后暂不运行在这里插入图片描述
在这里插入图片描述
然后将next()(取下一个任务)中的优先级比较换成了para.priority+(para.schedPolicy==SCHED_RR?1:0)*MAX_PRIORITY_NUM;就可以再解决非实时任务
将之前的tsk1和tsk2都改成SCHED_RR,如图在这里插入图片描述

实验总结:

gdb是人类的好朋友,GNU是最好的项目;kali比ubuntu好用多了;
操作系统实验真难;没用gdb之前总想在next()那里放个myPirntf(),可惜总是报时间偏移,估计是GPU远比IO快的原因,我就不一样了,我的大脑就跟不上我手,所以用了gdb后没多久就做出来了😄

参考资料:

gdb调试的基本使用
linux使用—8.用qemu调试linux内核

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值