1.多任务和任务切换,还有X86任务切换的原理都在我前面的文章中,已经写明,读者可以自行查看或百度

2.多任务的结构体

采用时间片轮转,优先调度
①一个任务的组成Task 是由段选择子(或可以称之为任务选择子,二者没有区别,因为一个任务 就是注册在GDT/LDT中)标志位,任务优先级, 该任务的现场和他可以占用cpu的权重构成
②我们所创建的多任务 是一个多级LEVEL,每个LEVEL中还分权重来决定占用CPU的时间,当高级LEVEL中有任务正在运行的时候,低级LEVEL是不能运行的,而且高级LEVEL可以抢占CPU
③TaskLevel 是记录当前这个LEVEL他里面有几个正在跑的任务,当前正在跑的那个任务的ID
④TaskCTL 记录当前占用CPU的是哪个级别,在下次任务切换时是否需要更新级别。

#define MAX_TASKS 1000   //最大任务数量
#define TASK_GAT_BEGIN 3 //定义从GDT的几号 开始分配给TSS的
#define ONE_LEVEL_MAX_TASK 100 //每个级别最大任务个数
#define MAX_LEVELS  10 //最多可以分成10个级别#define TASK_RUNNING    2
#define TASK_ALLOCED    1
#define TASK_NOT_USE    0struct TSS32
{int FrontWork;//上一个任务 16位int ESP0;//堆栈0int SS0;int ESP1;int SS1;int ESP2;int SS2;int CR3;//CR3含有存放页目录表页面的物理地址int EIP, EFLAGS, EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI;//寄存器int ES, CS, SS, DS, FS, GS;int LDTR, IOMAP;
};struct TASK
{int nSelector;//存放在GDT的几号int nFlags;int nLevel;//设定任务的优先级struct TSS32 Tss;int nPriority;//设定任务可占用CPU的时间
};struct TASKLEVEL
{int RunCounts;//有几个任务正在运行int CurRunId;//正在运行的任务IDstruct TASK   *pTask[ONE_LEVEL_MAX_TASK];//每个级别100 个任务};struct TASKCTL
{int CurLevel; //当前的Levelchar LevelChange; //下次任务切换时 是否需要改变levelstruct TASKLEVEL TaskLevelArr[MAX_LEVELS];// 最多10个级别struct TASK TaskArr[MAX_TASKS];// 1000个任务
};

2.定时器中断所做的事情 任务切换

void IntHandler20(int *pEsp)//定时器中断IRQ0
{//任务超时定时器标志位char TaskTimerFlag = 0;struct TIMER *pTimerTemp;io_out8(PIC0_OCW2, 0x60);//每次中断+1 来计数TimerCtl.u32Count++;//下一个需要比较的时间 未到 那么什么也不做if(TimerCtl.u32Next > TimerCtl.u32Count){return;}//把定时器链表的 头结点 赋值给 TemppTimerTemp = TimerCtl.pTimerHead;//Temp 在循环结束时候 是第一个未超时的那个 或者都超时了 while(1){//一直运行到 不超时那个TIMER 为止 因为pTimer数组是经过排序的if(pTimerTemp->u32TimeOut > TimerCtl.u32Count){break;}//处理超时的定时器pTimerTemp->u32Flag = TIMER_FLAGS_ALLOC;//如果不是任务切换定时器if(pTimerTemp != g_pTaskTimer){FifoSaveData(pTimerTemp->pFifo, pTimerTemp->nData);}else{TaskTimerFlag = 1;}pTimerTemp = pTimerTemp->pNext;}//改变头结点TimerCtl.pTimerHead = pTimerTemp;TimerCtl.u32Next = TimerCtl.pTimerHead->u32TimeOut;if(0 != TaskTimerFlag){TaskSwitch();}return;
}

3.具体实现

虽然前面原理什么的都讲了,但是我这里还是简单介绍一下吧,我们在Init中把所有的任务都注册到GDT表中,当任务要发生切换的时候,TR寄存器保存的是当前正在运行的任务,然后保存现场,然后把新的TSS的数据复制到寄存器里面

//命令行任务
void ConsoleTask(struct SHEET *pSheet);struct TASK *InitTask(struct MEMORY_MAN * MenMan);//新增一个任务
struct TASK *TaskAlloc(void);//运行一个任务
void TaskRun(struct TASK *pTask, int Level, int Priority);//任务切换
void TaskSwitch(void);//任务休眠
void TaskSleep(struct TASK *pTask);//获取当前正在运行的任务
struct TASK * GetCurTask(void);//向TASKLEVEL中添加一个任务
void AddTaskToLevel(struct TASK *pTask);//从TASKLEVEL中删除一个任务
void RemoveTaskFromLevel(struct TASK *pTask);//决定要跳转到哪个级别
void TaskSwitchLevel(void);//最低级的任务 当所有的任务 都休眠时 使系统进入省电模式
void TaskIdle(void);
#include "Tss.h"
#include "Timer.h"
#include "MyAsmFun.h"
#include "dsctbl.h"
#include "Sheet.h"
#include "graphic.h"
#include <stdio.h>
#include "fifo.h"//管理任务的定时器
struct TIMER *g_pTaskTimer;
//任务管理的结构体
struct TASKCTL *g_pTaskCtl;void (*pFunConsoleTask)(struct SHEET *pSheet) = ConsoleTask;//命令行任务
void ConsoleTask(struct SHEET *pSheet)
{struct FIFO Fifo32;struct TIMER *pTimer;struct TASK *pTask = GetCurTask();//用于使自己休眠int i;int FifoBuf[128];int CursorX = 8;int CursorColor = COL8_BLACK;InitFifo(&Fifo32, 128, FifoBuf, pTask);pTimer = GetTimer();TimerInit(pTimer, & Fifo32, 1);SetTimer(pTimer, 50);while (1){io_cli();if(0 == FifoStatus(&Fifo32)){TaskSleep(pTask);io_sti();}else{i = FifoReadData(&Fifo32);io_sti();if(i <= 1)//光标定时器{if(0 != i){TimerInit(pTimer, &Fifo32, 0);CursorColor = COL8_BLACK;}else{TimerInit(pTimer, &Fifo32, 1);CursorColor = COL8_WHITE;   }SetTimer(pTimer, 50);DrawBoxFillColor8(pSheet->pu8Buf, pSheet->nBxSize, CursorColor, CursorX, 28, CursorX+7, 43);SheetRefresh(pSheet, CursorX, 28, CursorX+8, 44);}}}}struct TASK *InitTask(struct MEMORY_MAN *MenMan)
{int i;struct TASK *pTask;//这是任务A的struct TASK *pTaskIdle;//任务哨兵 //将0x00270000开始的地址 存放GDT表 0x270000-0x27ffffstruct SEGMENT_DESCRIPTOR *pGDT_Add = (struct SEGMENT_DESCRIPTOR *)ADR_GDT;//为任务管理分配内存g_pTaskCtl = (struct TASKCTL *)MemoryManagerMalloc4K(MenMan, sizeof(struct TASKCTL));//任务初始化for (i = 0; i < MAX_TASKS; i++){g_pTaskCtl->TaskArr[i].nFlags = TASK_NOT_USE;                //没有使用g_pTaskCtl->TaskArr[i].nSelector = (TASK_GAT_BEGIN + i) * 8; //设置选择子SetSegmDesc(pGDT_Add + i + TASK_GAT_BEGIN, 103, (int)&(g_pTaskCtl->TaskArr[i].Tss), AR_TSS32);}for (i = 0; i < MAX_LEVELS; i++){g_pTaskCtl->TaskLevelArr[i].RunCounts = 0;g_pTaskCtl->TaskLevelArr[i].CurRunId = 0;}pTaskIdle = TaskAlloc();pTaskIdle->Tss.ESP = MemoryManagerMalloc4K(MenMan, 64*1024) + 64*1024;pTaskIdle->Tss.EIP = (int)&TaskIdle;pTaskIdle->Tss.ES = 1*8;pTaskIdle->Tss.CS = 2*8;pTaskIdle->Tss.SS = 1*8;pTaskIdle->Tss.DS = 1*8;pTaskIdle->Tss.FS = 1*8;pTaskIdle->Tss.GS = 1*8;TaskRun(pTaskIdle, MAX_LEVELS-1, 1);//新增一个任务pTask = TaskAlloc();pTask->nFlags = TASK_RUNNING; //活动中标志pTask->nPriority = 2;//0.02SpTask->nLevel = 0;//设为最高级别AddTaskToLevel(pTask);TaskSwitchLevel();load_tr(pTask->nSelector);g_pTaskTimer = GetTimer();SetTimer(g_pTaskTimer, pTask->nPriority);return pTask;
}struct TASK *TaskAlloc(void)
{int i;struct TASK *pTask;for (i = 0; i < MAX_TASKS; i++){//如果没有使用的话if (TASK_NOT_USE == g_pTaskCtl->TaskArr[i].nFlags){pTask = &(g_pTaskCtl->TaskArr[i]);pTask->nFlags = TASK_ALLOCED;pTask->Tss.EFLAGS = 0x00000202;pTask->Tss.EAX = 0;pTask->Tss.ECX = 0;pTask->Tss.EDX = 0;pTask->Tss.EBP = 0;pTask->Tss.EBX = 0;pTask->Tss.EDI = 0;pTask->Tss.ESI = 0;pTask->Tss.ES = 0;pTask->Tss.DS = 0;pTask->Tss.FS = 0;pTask->Tss.GS = 0;pTask->Tss.LDTR = 0;pTask->Tss.IOMAP = 0x40000000;return pTask;}}return 0;
}//运行一个任务
void TaskRun(struct TASK *pTask, int Level, int Priority)
{//不改变优先级if (Level < 0){Level = pTask->nLevel;}//如果是0的话 那么就不改变优先级if (Priority > 0){pTask->nPriority = Priority;}if((TASK_RUNNING == pTask->nFlags) && (pTask->nLevel != Level)) //改变活动中的Level{RemoveTaskFromLevel(pTask);}if(TASK_RUNNING != pTask->nFlags){pTask->nLevel = Level;AddTaskToLevel(pTask);}g_pTaskCtl->LevelChange = 1;    //下次任务切换时, 检查Levelreturn;
}//任务切换
void TaskSwitch(void)
{struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);struct TASK *pNewTask;struct TASK *pCurTask = pTaskLevel->pTask[pTaskLevel->CurRunId];pTaskLevel->CurRunId++;if (pTaskLevel->CurRunId == pTaskLevel->RunCounts){pTaskLevel->CurRunId = 0;}if(0 != g_pTaskCtl->LevelChange){TaskSwitchLevel();pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);}pNewTask = pTaskLevel->pTask[pTaskLevel->CurRunId];SetTimer(g_pTaskTimer, pNewTask->nPriority);if(pNewTask != pCurTask){farjmp(0, pNewTask->nSelector);}return;
}//任务休眠
void TaskSleep(struct TASK *pTask)
{struct TASK *pCurTask;//如果指定的任务处于运行状态if (TASK_RUNNING == pTask->nFlags){pCurTask = GetCurTask();RemoveTaskFromLevel(pTask);//如果是要自我休眠if (pTask == pCurTask){TaskSwitchLevel();pCurTask = GetCurTask();farjmp(0, pCurTask->nSelector);}}return;
}//获取当前正在运行的任务
struct TASK * GetCurTask(void)
{struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[g_pTaskCtl->CurLevel]);return (pTaskLevel->pTask[pTaskLevel->CurRunId]);
}//向TASKLEVEL中添加一个任务
void AddTaskToLevel(struct TASK *pTask)
{//获取到该任务 所属级别的 结构体地址struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[pTask->nLevel]);/*if (pTaskLevel->RunCounts >= ONE_LEVEL_MAX_TASK){return;}*///将该任务 加到数组中 正在运行的+1pTaskLevel->pTask[pTaskLevel->RunCounts] = pTask;pTaskLevel->RunCounts++;pTask->nFlags = TASK_RUNNING;return;
}//从TASKLEVEL中删除一个任务
void RemoveTaskFromLevel(struct TASK *pTask)
{int i;//获取到该任务 所属级别的 结构体地址struct TASKLEVEL *pTaskLevel = &(g_pTaskCtl->TaskLevelArr[pTask->nLevel]);/*if(pTaskLevel->RunCounts < 0){return;}*///寻找Task出现在数组中的位置for (i = 0; i < pTaskLevel->RunCounts; i++){if (pTaskLevel->pTask[i] == pTask){break;}}pTaskLevel->RunCounts--;//如果当前要删除的任务 位置处在正在运行的任务的前面if(i < pTaskLevel->CurRunId){pTaskLevel->CurRunId--;}if (pTaskLevel->CurRunId >= pTaskLevel->RunCounts){pTaskLevel->CurRunId = 0;}pTask->nFlags = TASK_ALLOCED;//休眠//移动处理for (; i < pTaskLevel->RunCounts; i++){pTaskLevel->pTask[i] = pTaskLevel->pTask[i + 1];}return;
}//决定要跳转到哪个级别
void TaskSwitchLevel(void)
{int i;for ( i = 0; i < MAX_LEVELS; i++){if (g_pTaskCtl->TaskLevelArr[i].RunCounts > 0){break;    }}g_pTaskCtl->CurLevel = i;g_pTaskCtl->LevelChange = 0;return;
}//最低级的任务 当所有的任务 都休眠时 使系统进入省电模式
void TaskIdle(void)
{while(1){io_hlt();}
}

Day15Day16多任务和任务切换相关推荐

  1. linux多任务切换快捷键,Windows 10十月更新导致Alt+Tab多任务切换快捷键出错

    Windows 10的十月更新虽然相比上半年的五月更新只是一个小升级,但是它带来了两个新功能,一个是主题感知的开始菜单,一个就是新的Alt+Tab体验. Alt+Tab是Windows 2.0以来一直 ...

  2. <X86汇编语言:实模式到保护模式>四十四 协同式任务切换

    多任务和任务切换概述 什么时候切换到另一个任务? 以及切换到哪一个任务? 都是操作系统决定. 内核任务的创建和I/O特权级IOPL 0特权级始终高于或等于 IOPL 先使用and,将iopl清0,再使 ...

  3. python 协程_Python多任务协程

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源).为啥说它是一个执行单元,因为它自带CPU ...

  4. X86汇编语言从实模式到保护模式17:协同式任务切换

    目录 1. 多任务和任务切换概述 1.1 多任务系统 1.2 任务切换含义 1.2.1 切换任务上下文 1.2.2 上下文是什么 1.3 任务切换方式概述 1.3.1 协同式任务切换 1.3.2 抢占 ...

  5. 菜鸟IT技术杂谈(一)——从多任务系统原理说起

    怎么说我最近的状态呢? 不是特别好,但是也还是可以,老板也对自己不错.过得还算开心. 这个系列的博文,算是自己自己这两三年来学到的东西的理解吧. 不会对大家产生立竿见影的效果,只是拿自己学习到的东西做 ...

  6. python 多任务

    一些概念 1.多任务 简单地说,就是同时可以运行多个任务.打个比方,你一边在用浏览器上网,一边在听MP3,一边在用Word赶作业,这就是多任务. 2.并行 指的是任务数小于等于cpu核数,在一段时间内 ...

  7. python多任务—协程(一)

    写在前面: 花了一周的时间,对协程做了一个简单的梳理,特别是异步编程asyncio库的使用,做了详细的说明.本文主要包括的知识点有:yield生成器的复习并实现协程的功能.greenlet库实现协程. ...

  8. 智能车竞赛技术报告 | 电磁越野组 - 哈尔滨工业大学 - 紫丁香三队

    简 介: 本文详细介绍了我们为了十六届全国大学生智能车大赛室外越野组准备的车模.车模采用Infineon公司的TC377芯片作为控制器,通过电感采集数据,并离线训练神经网络,后使用nnom部署到单片机 ...

  9. APP中的悬浮球设计总结

    本文为PMCAFF专栏作者836488572出品 如果问我过去一段时间最令人印象深刻的交互方式有哪些?我想说的有两个:一个是微信的文章浮窗,在阅读文章时,如果有紧急信息需要处理,可以把文章加入浮窗,想 ...

  10. python中协程实现的本质以及两个封装协程模块greenle、gevent

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程是啥 协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源). 为啥说它是一个执行单元,因为 ...

最新文章

  1. 硅谷产学研的创新循环
  2. 字节跳动花50亿买了个什么?
  3. 如何将JBoss HR员工奖励项目放入云端
  4. es6 Generator函数的this
  5. 解决python在pycharm中可以import本地文件,但命令行运行时报错:no model named xxxx本地文件
  6. 深度优先搜索(DFS)和广度优先搜索(BFS)探究
  7. 禅道PMS兼容redmine用户认证接口
  8. heartbeat 非联网安装(通过配置本地yum文件库安装heartbeat)
  9. 第10章 分离并纠正物理层和数据链路层故障
  10. Java运行Shell脚本
  11. 网课查课插件 支持 60类型+ 彩虹查课插件 网络查课查询
  12. 查询linux安装了哪种中文,linux 安装 中文字体
  13. windows10远程桌面 删除IP记录
  14. 修改docker ip网段
  15. 苹果怎么换行打字_好玩的微信空白朋友圈怎么发?教程来了!
  16. 正文样式设置必看:你知道最好不要直接在正文样式中设置首行缩进吗
  17. 洛谷4168 [Violet]蒲公英
  18. 酷炫一款动态背景(HTML +js canvas)
  19. spynet(一):光流估计代码介绍
  20. 数理方程与特殊函数|波动方程:弦的横振动方程

热门文章

  1. logback介绍和配置详解
  2. load与DOMContentLoaded
  3. 35、【华为HCIE-Storage】--快照
  4. 改善C#程序的建议9:使用Task代替ThreadPool和Thread
  5. 算法(四)、时间复杂度、排序、查找
  6. 割裂的前端工程师--- 2017年前端生态窥探
  7. 设置SQLSERVER的错误日志数量和查找SQLSERVER安装错误日志
  8. 产品设计体会(8007)产品经理的主要职责
  9. react 结合 axios 异步请求封装
  10. Android的Splash界面支持用户点击