首页
导航
博客
电子书
算法
众创
代码
随贴
关于我们
您好,欢迎来到码863代码分享网! 请
[登录]
/
[注册]
搜 索
标题:
*
140
字
TAG标签:
(用空格隔开)
30
字
恢复历史版本:
请选择分类
html
python
javascript
php
sql
c
c++
c#
java
plain
所有人可见
仅自己可见
编辑器:UEditor
编辑器:TinyMCE
编辑器:Editor.md
HTML转MD
HTML转MD2
<p>一<span style="white-space:pre;"> </span>这个分析是我最早看该书多任务的时候做的笔记,不过到底是基于哪一节的代码做的我实在是忘记了,但是删了又可惜,就留着吧。。。</p> <p> 1. task_a = Task_init(memman), 进入Task_init函数中,它会创建一个TASKCTL结构体, 并将该结构体地址赋给taskctl, 这是一个全局变量。然后初始化该结构体中所有的TASK结构。包括创建这些TASK结构的段描述符并保存到GDT中。(GDT中从序号为3的描述符开始全部都是TSS的描述符,没有LDT的描述符,很奇怪。。。)。然后调用task_alloc()函数从刚刚创建的TASKCTL结构体中找到一个未用的TASK结构, 并对其结构体中的TSS域做初始化,然后该函数返回该TASK结构的地址给task变量,这是一个局部变量。将这个TASK结构的flag域赋值为2,表示正在活动。修改taskctl结构中的running = 1,表示已经有一个任务在运行,taskctl的now = 0, 表示当前运行的任务是taskctl结构中tasks数组中的下标为0的TASK结构指针指向的TASK。然后将taskctl中tasks数组中下标为0的元素改为task,也就是我们刚刚找到的第一个未用的TASK结构的地址。然后修改tr寄存器,使其等于task中的sel,然后再创建一个定时器task_timer,再将该定时器的timeout设为2,(这个定时器很重要,用于任务切换)最后返回task,回到HarMain中, HarMain中会将返回的task赋给task_a。注意!!这个时候HarMain已经是任务A了!!!虽然 在task_init中虽然设置了定时器, 但是由于现在系统中只有一个任务 所以不会进行任务切换。task_switch中会判断</p> <p>2. Fifo.task = task_a, task_a是上面初始化的TASK结构。表示如果fifo有数据进入就唤醒任务a</p> <p>3. . task_b = task_alloc();创建task_b, 接着为其分配内存用来创建它自身的栈,修改其TSS域中的各个寄存器的值。最后,task_run(task_b)。该函数会将task_b的地址赋值给taskctl结构中的tasks域的某一元素。(tasks是task结构指针的有序数组)然后修改running的值,最后直接返回。注意,现在task_b已经加入到正在运行的队伍中了,所以当task_timer定时器发生时钟中断时,是会转到task_b任务运行的。</p> <p> <span style="white-space:pre;"> </span>假设现在发生了task_timer定时器中断 那么在中断处理函数中会调用任务切换函数 task_switch会重新设置task_timer定时器并判断任务数是否大于等于2, 现在任务数为2.所以会跳转到任务2去运行</p> <p> </p> <p>二<span style="white-space:pre;"> </span>这个分析是对第十六天的最终代码做的分析</p> <p>首先是任务A</p> <p>在HarMain中被创建(70行 task_a = task_init(memman);<span style="white-space:pre;"> </span>)从此HarMain函数运行于任务A中。</p> <p>任务A现在的状态: flag = 2(活动中标志), level = 0(最高LEVEL)。我们只关注这两个变量。<span style="white-space:pre;"> </span>任务管理结构taskctl现在的状态:now_lv = 0, lv_change = 0。我们也只关心这个结构的这两个成员变量。</p> <p>任务A所在的LEVEL结构的状态:running = 1, now = 0。同样只关心这两个成员变量。</p> <p>在task_init()中还设定了task_timer定时器,这个定时器用于任务切换。定时器时间设定为任务A的优先级。从现在开始已经可以利用该定时器完成任务切换了,但是因为现在只有一个任务在系统中运行,所以实际上不会被切换。我们来看下在当前系统中只有一个任务在执行时,task_switch(void)函数的执行情况。该函数只在inthandler20()函数中被调用(这是时钟中断处理函数)。首先tl->now++,这时候now == running了(在task_init中被设置成这样的),所以tl->now = 0。由于lv_change = 0,所以不需要检测level,new_task就等于任务A,所以不需要执行farjmp执行切换,所以实际上它并没有做什么事情。</p> <p>继续看HarMain函数,fifo.task = task_a;,说明当FIFO有数据写入的时候要唤醒的是任务A。task_run(task_a, 1, 2); 这里修改了任务A的level,将它从level0降到了level1。此时LEVEL结构中的now == running = 0。注意:此时taskctl->lvchange = 1,taskctl->now_lv = 0(now_lv除了初始化就只有在task_switchsub()中才会被更改,这个时候的now_lv是不正确的,因为任务A现在是处于level1),而且现在任务A是在LEVEL1中。我们假设这个时候发生task_timer定时器超时,执行转到inthandler20(),该函数最终调用task_switch(void)函数,还函数中的局部变量tl最新指向的是level0的结构体,now_task也是level0结构体中的某个task指针(可以认为它们都是错误的),tl->now++(错误的将level0的now做了自增)。而且此处也不会调整now值,因为这个时候running=0。但是这个时候lv_change由于不等于0,所以要检测level。调用task_switchsub(),该函数修改taskctl->now_lv = 1, taskctl->lv_change = 0。tl现在指向了正确的LEVEL结构。由于New_task == now_task(它们都指向任务A的TASK结构)。所以不会发生任务切换。</p> <p>再关注下HarMain函数的第103行task_run(task_b[i], 2, i + 1);将任务B[i]逐个添加进去。如果这个时候发生task_timer定时器超时的话,由于任务A运行在比任务B[i]更高等级的层上,所以任务B不会被执行。</p> <p>最后看HarMain函数的第149行,task_sleep(task_a);如果这个时候我们按下键盘、移动鼠标或者产生非task_timer的时钟中断(此处只有光标闪烁那个定时器会产生该种类型的时钟中断,任务B中的定时器对FIFO缓冲区的操作对HarMain中的缓冲区没有影响),任务A就不会睡眠,否则任务A将执行该函数调用语句进行睡眠。如果要睡眠,则要发生任务切换,看task_sleep函数中当发现要睡眠的是自己时,就调用task_switchsub();它会将taskctl->now_lv设置为2,也就是任务B的level等级,taskctl->lv_change = 0。然后切换到任务B[0]中运行。此时任务B[0]的函数体得到运行task_b_main()。如果这个时候只有光标闪烁定时器、键盘或鼠标中断发生时才会切回到任务A。看fifo32_put()函数,在它最后会调用task_run(fifo->task, -1, 0); fifo->task就是任务A的地址,-1表示level不变,0表示优先级不变。Task_run会将任务A添加到Level1中并设置lv_change = 1。但是现在任务A还没有立刻运行,等到下一次task_timer定时器超时的时候调用task_switch()函数才回切换到任务A中运行</p>
CopyRight 2002~2023 精通2100网 联系邮箱:qqtxt@163.com
版权所有:精通2100网
湘ICP备2023018646号-1
MYSQl共执行 4 个查询,用时 0.0022437572479248 秒,PHP脚本用时 0.004440 秒,占用内存 0.527 MB,Gzip 已启用