当前位置: 首页 > news >正文

Day16 多任务(2)

文章目录

      • 1. 任务管理自动化(harib13a)
      • 2. 任务休眠(harib13b)
      • 3. 增加窗口数量(harib13c)
      • 4. 设定任务优先级(1)(harib13d)
      • 5. 设定任务优先级(2)(harib13e)

1. 任务管理自动化(harib13a)

使用定时器和窗口那种处理方式处理多线程的切换。

// bootpack.h文件
#define ADR_GDT			0x00270000
#define MAX_TASKS		1000	/* 最大任务数量 */
#define TASK_GDT0		3		/* 定义从GDT的几号开始分配给TSS */
struct TSS32 {int backlink, esp0, ss0, esp1, ss1, esp2, ss2, 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 sel, flags; /* sel存放GDT的编号 */struct TSS32 tss;
};
struct TASKCTL {int running; /* 正在运行的任务数量 */int now; /* 用来记录当前正在运行的是哪个任务 */struct TASK *tasks[MAX_TASKS];	// 参与到调度的taskstruct TASK tasks0[MAX_TASKS];	// 预留出最大task内存
};// mtask.c文件
struct TASK *task_init(struct MEMMAN *memman)
{int i;struct TASK *task;struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));for (i = 0; i < MAX_TASKS; i++) {taskctl->tasks0[i].flags = 0; /* 先标识为未使用 */taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);}task = task_alloc();task->flags = 2; /* 标识为活动中 */taskctl->running = 1;taskctl->now = 0;taskctl->tasks[0] = task;load_tr(task->sel);task_timer = timer_alloc();timer_settime(task_timer, 2);return task;
}struct TASK *task_alloc(void)
{int i;struct TASK *task;for (i = 0; i < MAX_TASKS; i++) {if (taskctl->tasks0[i].flags == 0) {task = &taskctl->tasks0[i];task->flags = 1; /* 标识为正在使用 */task->tss.eflags = 0x00000202; /* IF = 1; */task->tss.eax = 0; /* 暂且先赋值为0 */task->tss.ecx = 0;task->tss.edx = 0;task->tss.ebx = 0;task->tss.ebp = 0;task->tss.esi = 0;task->tss.edi = 0;task->tss.es = 0;task->tss.ds = 0;task->tss.fs = 0;task->tss.gs = 0;task->tss.ldtr = 0;task->tss.iomap = 0x40000000;return task;}}return 0; /* 全部正在使用 */
}void task_run(struct TASK *task)
{task->flags = 2; /* 标识为活动中 */taskctl->tasks[taskctl->running] = task;taskctl->running++;return;
}void task_switch(void)
{timer_settime(task_timer, 2);if (taskctl->running >= 2) {taskctl->now++;if (taskctl->now == taskctl->running) {taskctl->now = 0;}farjmp(0, taskctl->tasks[taskctl->now]->sel);}return;
}
// bootpack.c
void HaribMain(void)
{struct TASK *task_b;task_init(memman);task_b = task_alloc();task_b->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;task_b->tss.eip = (int) &task_b_main;task_b->tss.es = 1 * 8;task_b->tss.cs = 2 * 8;task_b->tss.ss = 1 * 8;task_b->tss.ds = 1 * 8;task_b->tss.fs = 1 * 8;task_b->tss.gs = 1 * 8;*((int *) (task_b->tss.esp + 4)) = (int) sht_back;task_run(task_b);/* 省略 */	
}

需要增加task的时候只需要调用task_alloc和task_run就可以了。

2. 任务休眠(harib13b)

由于任务A中主要做鼠标,键盘,定时器的处理操作(打印),所以当没有这些动作时,任务A是空闲的(HLT),但是任务B却一直在工作。本节期望实现当任务A空闲的时候就使任务A休眠,当有对应的中断过来,再唤醒它。

// mtask.c
void task_sleep(struct TASK *task)
{int i;char ts = 0;if (task->flags == 2) {		/* 如果该任务处于活动中 */if (task == taskctl->tasks[taskctl->now]) {ts = 1; /* 让本task休眠的话,稍后需要进行任务切换 */}/* 寻找task所在的位置,让该task休眠 */for (i = 0; i < taskctl->running; i++) {if (taskctl->tasks[i] == task) {break;}}taskctl->running--;if (i < taskctl->now) {taskctl->now--;}/* 移动成员 */for (; i < taskctl->running; i++) {taskctl->tasks[i] = taskctl->tasks[i + 1];}task->flags = 1; /* 不工作的状态 */if (ts != 0) {/* 本进程休眠,任务切换 */if (taskctl->now >= taskctl->running) {/* 如果now的值出现异常,则进行修正 */taskctl->now = 0;}farjmp(0, taskctl->tasks[taskctl->now]->sel);}}return;
}

修改FIFO定义,使缓冲区中有数据写入时将任务唤醒:

// bootpack.h
struct FIFO32 {int *buf;int p, q, size, free, flags;struct TASK *task;
};// fifo.c
void fifo32_init(struct FIFO32 *fifo, int size, int *buf, struct TASK *task)
{fifo->size = size;fifo->buf = buf;fifo->free = size; /* 剩余空间 */fifo->flags = 0;fifo->p = 0; /* 写入位置 */fifo->q = 0; /* 读取位置 */fifo->task = task; /* 新增 */return;
}int fifo32_put(struct FIFO32 *fifo, int data)
{if (fifo->free == 0) {/* 无剩余空间,则溢出 */fifo->flags |= FLAGS_OVERRUN;return -1;}fifo->buf[fifo->p] = data;fifo->p++;if (fifo->p == fifo->size) {fifo->p = 0;}fifo->free--;if (fifo->task != 0) {if (fifo->task->flags != 2) { /* 新增,先判断是否已经处于唤醒状态 */task_run(fifo->task); /* 如果任务处于休眠状态,则唤醒 */}}return 0;
}// bootpack.c
void HariMain(void)
{struct TASK *task_a, *task_b;fifo32_init(&fifo, 128, fifobuf, 0);task_a = task_init(memman);fifo.task = task_a;task_b = task_alloc();for (;;) {io_cli();	// 屏蔽中断请求if (fifo32_status(&fifo) == 0) {task_sleep(task_a);	// 屏蔽中断请求的状态下进行休眠io_sti();}else{// 省略}}
}void task_b_main(struct SHEET *sht_back)
{fifo32_init(&fifo, 128, fifobuf, 0);
}

3. 增加窗口数量(harib13c)

增加新的任务,最终使共4个任务,并分别命名为task_a,task_b0,task_b1,task_b2。对每个任务分配一个窗口。
此外,还删除了task_a的3秒定时器和10秒定时器。

// bootpack.c
void HaribMain(void)
{unsigned char *buf_back, buf_mouse[256], *buf_win, *buf_win_b;struct SHEET *sht_back, *sht_mouse, *sht_win, *sht_win_b[3];struct TASK *task_a, *task_b[3];struct TIMER *timer;init_palette();shtctl = shtctl_init(memman, binfo->vram, binfo->scrnx, binfo->scrny);task_a = task_init(memman);		// 主线程还是task_afifo.task = task_a;/* sht_back */sht_back  = sheet_alloc(shtctl);buf_back  = (unsigned char *) memman_alloc_4k(memman, binfo->scrnx * binfo->scrny);sheet_setbuf(sht_back, buf_back, binfo->scrnx, binfo->scrny, -1); /* 无透明色 */init_screen8(buf_back, binfo->scrnx, binfo->scrny);/* sht_win_b */for (i = 0; i < 3; i++) {sht_win_b[i] = sheet_alloc(shtctl);buf_win_b = (unsigned char *) memman_alloc_4k(memman, 144 * 52);sheet_setbuf(sht_win_b[i], buf_win_b, 144, 52, -1); /* 无透明色 */sprintf(s, "task_b%d", i);make_window8(buf_win_b, 144, 52, s, 0);task_b[i] = task_alloc();task_b[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;task_b[i]->tss.eip = (int) &task_b_main;task_b[i]->tss.es = 1 * 8;task_b[i]->tss.cs = 2 * 8;task_b[i]->tss.ss = 1 * 8;task_b[i]->tss.ds = 1 * 8;task_b[i]->tss.fs = 1 * 8;task_b[i]->tss.gs = 1 * 8;*((int *) (task_b[i]->tss.esp + 4)) = (int) sht_win_b[i];task_run(task_b[i]);}/* sht_win */sht_win   = sheet_alloc(shtctl);buf_win   = (unsigned char *) memman_alloc_4k(memman, 160 * 52);sheet_setbuf(sht_win, buf_win, 144, 52, -1); /* ���F��� */make_window8(buf_win, 144, 52, "task_a", 1);make_textbox8(sht_win, 8, 28, 128, 16, COL8_FFFFFF);cursor_x = 8;cursor_c = COL8_FFFFFF;timer = timer_alloc();timer_init(timer, &fifo, 1);timer_settime(timer, 50);/* sht_mouse */sht_mouse = sheet_alloc(shtctl);sheet_setbuf(sht_mouse, buf_mouse, 16, 16, 99);init_mouse_cursor8(buf_mouse, 99);mx = (binfo->scrnx - 16) / 2; /* 计算坐标,使其位于画面中央 */my = (binfo->scrny - 28 - 16) / 2;sheet_slide(sht_back, 0, 0);sheet_slide(sht_win_b[0], 168,  56);sheet_slide(sht_win_b[1],   8, 116);sheet_slide(sht_win_b[2], 168, 116);sheet_slide(sht_win,        8,  56);sheet_slide(sht_mouse, mx, my);sheet_updown(sht_back,     0);sheet_updown(sht_win_b[0], 1);sheet_updown(sht_win_b[1], 2);sheet_updown(sht_win_b[2], 3);sheet_updown(sht_win,      4);sheet_updown(sht_mouse,    5);sprintf(s, "(%3d, %3d)", mx, my);putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);sprintf(s, "memory %dMB   free : %dKB",memtotal / (1024 * 1024), memman_total(memman) / 1024);putfonts8_asc_sht(sht_back, 0, 32, COL8_FFFFFF, COL8_008484, s, 40);
}

在这里插入图片描述

4. 设定任务优先级(1)(harib13d)

当前的B0 ~ B2这三个任务,都是以0.02s的时间间隔进行任务切换,修改一下唉,使其可以在0.01s ~ 0.1s的时间范围内设定不同的任务切换。即优先级越高的任务,切换的频率越高,则调度到的次数越多。0.01s ~ 0.1s的差异可实现最大10倍的优先级差异。

struct TASK {int sel, flags;int priority;	// 添加优先级字段struct TSS32 tss;
};struct TASK *task_init(struct MEMMAN *memman)
{int i;struct TASK *task;struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));for (i = 0; i < MAX_TASKS; i++) {taskctl->tasks0[i].flags = 0;taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);}task = task_alloc();task->flags = 2; /* 标识为活动中 */task->priority = 2; /* 初始化为0.02s */taskctl->running = 1;taskctl->now = 0;taskctl->tasks[0] = task;load_tr(task->sel);task_timer = timer_alloc();timer_settime(task_timer, task->priority);return task;
}void task_run(struct TASK *task, int priority)
{	// 调用时传入优先级参数if (priority > 0) {task->priority = priority;}// 如果传入priority为0,则唤醒任务 if (task->flags != 2) {task->flags = 2; /* 标识为活动中 */taskctl->tasks[taskctl->running] = task;taskctl->running++;}return;
}void task_switch(void)
{struct TASK *task;taskctl->now++;if (taskctl->now == taskctl->running) {taskctl->now = 0;}task = taskctl->tasks[taskctl->now];timer_settime(task_timer, task->priority);if (taskctl->running >= 2) {farjmp(0, task->sel);}return;
}/* fifo.c */
int fifo32_put(struct FIFO32 *fifo, int data)
{if (fifo->free == 0) {fifo->flags |= FLAGS_OVERRUN;return -1;}fifo->buf[fifo->p] = data;fifo->p++;if (fifo->p == fifo->size) {fifo->p = 0;}fifo->free--;if (fifo->task != 0) {if (fifo->task->flags != 2) { /* 如果任务处于休眠 */task_run(fifo->task, 0); /* 唤醒 */}}return 0;
}

5. 设定任务优先级(2)(harib13e)

增加一个level结构体作为一类task的集合,本level中的task在活动中时,其他level的task就不应该被调度到。这样做是为了使即便等高优先级的任务同时运行,也可以分辨哪一个任务更加优先。
类似图中所示,最上层的level0中只要存在一个task,则完全忽略level1和level2中的task,只在level0的任务中进行切换。当level0中task全部休眠,或没有task时,就开始轮到level1中的task进行任务切换。
在这里插入图片描述

// bootpack.h
struct TASK {int sel, flags; /* sel用来存放GDT的编号 */int level, priority;	// 增加一个level字段,标识task实例是哪个levelstruct TSS32 tss;
};
struct TASKLEVEL {int running; /* 正在运行的任务数量 */int now; /* 用来记录当前运行的是哪个任务 */struct TASK *tasks[MAX_TASKS_LV];	// 每个level里管理的task
};
struct TASKCTL {int now_lv; /* 当前活动中的是哪个level */char lv_change; /* 下次任务切换时是否需要改变level */struct TASKLEVEL level[MAX_TASKLEVELS];struct TASK tasks0[MAX_TASKS];	// 预留出所有task的空间
};
// mtask.c
struct TASKCTL *taskctl;
struct TIMER *task_timer;struct TASK *task_now(void)
{struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];return tl->tasks[tl->now];
}void task_add(struct TASK *task)
{struct TASKLEVEL *tl = &taskctl->level[task->level];tl->tasks[tl->running] = task;tl->running++;task->flags = 2; /* 活动中 */return;
}void task_remove(struct TASK *task)
{int i;struct TASKLEVEL *tl = &taskctl->level[task->level];/* 寻找task所在的位置 */for (i = 0; i < tl->running; i++) {if (tl->tasks[i] == task) {break;}}tl->running--;if (i < tl->now) {tl->now--; /* 需要移动成员 */}if (tl->now >= tl->running) {/* 如果now的值出现异常,则进行修正 */tl->now = 0;}task->flags = 1; /* 休眠中 *//* 移动 */for (; i < tl->running; i++) {tl->tasks[i] = tl->tasks[i + 1];}return;
}void task_switchsub(void)
{	// 切换levelint i;/* 寻找最上层的level */for (i = 0; i < MAX_TASKLEVELS; i++) {if (taskctl->level[i].running > 0) {break; /* 找到 */}}taskctl->now_lv = i;	// 标识当前活动task所在的leveltaskctl->lv_change = 0;	// 不需要改变levelreturn;
}struct TASK *task_init(struct MEMMAN *memman)
{int i;struct TASK *task;struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));/* 省略 */for (i = 0; i < MAX_TASKLEVELS; i++) {taskctl->level[i].running = 0;taskctl->level[i].now = 0;}task = task_alloc();task->flags = 2;	/* 活动中 */task->priority = 2; /* 0.02s的频率切换 */task->level = 0;	/* level 0 */task_add(task);		/* 把主任务添加到level0中 */task_switchsub();	/* 切换到level0 */load_tr(task->sel);task_timer = timer_alloc();timer_settime(task_timer, task->priority);return task;
}void task_run(struct TASK *task, int level, int priority)
{if (level < 0) {level = task->level; /* 主要用于唤醒的时候,不改变level */}if (priority > 0) {task->priority = priority;}if (task->flags == 2 && task->level != level) { /* 如果已经在运行,并且level不同 */task_remove(task); /* 先移除该task,期间会把flags赋值为1,即标识为未运行 */}if (task->flags != 2) {/* 再修改level,并标识为活动中(flags赋值为2) */task->level = level;task_add(task);}taskctl->lv_change = 1; /* 下次任务切换时检查level */return;
}void task_sleep(struct TASK *task)
{struct TASK *now_task;if (task->flags == 2) {/* 当处于活动状态时 */now_task = task_now();	// 查看当前tasktask_remove(task); 		/* 把该task移除 */if (task == now_task) {/* 如果刚才移除的就是正在运行的task */task_switchsub();	// 就要进行level切换now_task = task_now(); /* 切换后在查看当前task */farjmp(0, now_task->sel);}}return;
}void task_switch(void)
{struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];struct TASK *new_task, *now_task = tl->tasks[tl->now];tl->now++;if (tl->now == tl->running) {tl->now = 0;}if (taskctl->lv_change != 0) {// 主要是增加了这个判断和相应的动作task_switchsub();tl = &taskctl->level[taskctl->now_lv];}new_task = tl->tasks[tl->now];timer_settime(task_timer, new_task->priority);if (new_task != now_task) {farjmp(0, new_task->sel);}return;
}
// fifo.c
int fifo32_put(struct FIFO32 *fifo, int data)
{/* 省略 */fifo->free--;if (fifo->task != 0) {if (fifo->task->flags != 2) { /* 如果处于休眠状态 */task_run(fifo->task, -1, 0); /* 唤醒 */}}return 0;
}

此外,在HariMain函数中,对task调用task_run(task_a, 1, 2);task_run(task_b[i], 2, i + 1);

http://www.lryc.cn/news/623854.html

相关文章:

  • USB-A 3.2 和 USB-A 2.0的区别
  • Day27 装饰器
  • 从零配置YOLOv8环境:RTX 3060显卡完整指南
  • AI评测的科学之道:当Benchmark遇上统计学
  • 48.Seata认识、部署TC服务、微服务集成
  • [Responsive theme color] 动态更新 | CSS变量+JS操控 | 移动端-汉堡菜单 | 实现平滑滚动
  • 实现用户输入打断大模型流式输出:基于Vue与FastAPI的方案
  • GaussDB 数据库架构师修炼(十三)安全管理(5)-全密态数据库
  • 【每日一题】Day 6
  • 凸函数与损失函数
  • 开源数据发现平台:Amundsen Search Service 搜索服务
  • Python注解
  • 零墨云A4mini打印机设置电脑通过局域网络进行打印
  • C#对象的本地保存与序列化详解笔记
  • GitLab CI/CD、Jenkins与GitHub Actions在Kubernetes环境中的方案对比分析
  • 【Golang】:错误处理
  • 任务型Agent架构简介
  • Visual Studio Code 基础设置指南
  • 【R语言】R 语言中打印含有双引号的字符串时会出现 “\” 的原因解析
  • GaussDB常用术语缩写及释义
  • 路由器配置之模式
  • 4.Ansible自动化之-部署文件到主机
  • nodejs 中间件
  • gitee 流水线+docker-compose部署 nodejs服务+mysql+redis
  • 【计算机网络面试】TCP/IP网络模型有哪几层
  • Matlab数字信号处理——基于最小均方误差(MMSE)估计的自适应脉冲压缩算法复现
  • ThinkPHP8学习篇(三):控制器
  • 7.Ansible自动化之-实施任务控制
  • 最优化:建模、算法与理论|02 Optimization Modeling and Typical Examples(1)
  • [优选算法专题二滑动窗口——将x减到0的最小操作数]