什么是 挂起迅雷只能下载一个任务务

java开发系统内核:进程的挂起和恢复 - 简书
java开发系统内核:进程的挂起和恢复
更详细的讲解和代码调试演示过程,请参看视频
有了进程的自动调度后,接下来的任务在于,如何将空闲进程挂起,空闲进程往往是那些没有具体任务需要处理的进程,因此,如果继续让其运行的话,那么必然会耗费宝贵的CPU资源,如果能让它先挂起,等到它需要执行具体任务时,再把它调度到前台,那才是一种合理的进程管理机制。
我们实现的进程调度,是依赖于进程控制器,也就是taskctl中的任务数组来实现的,当我们想要启动某个进程时,在该数组中找到对应的任务对象,然后把它加载到CPU那就可以了。
同理,如果要让某个进程休眠,那么只要把它对应的TASK对象从任务数组中移除,那么它自然就不会得到调度的机会。
因此,修改multi_task.c 增加一个task_sleep函数:
void task_sleep(struct TASK *task) {
char ts = 0;
if (task-&flags == 2) {
if (task == taskctl-&tasks[taskctl-&now]) {
for (i = 0; i & taskctl-& i++) {
//在任务数组中找到要挂起的进程对象
if (taskctl-&tasks[i] == task) {
taskctl-&running--;
if (i & taskctl-&now) {
taskctl-&now--;
for(; i & taskctl-& i++) {
//通过把后面的任务往前覆盖,实现将当前任务从任务列表中移除的目的
taskctl-&tasks[i] = taskctl-&tasks[i+1];
task-&flags = 1;
if (ts != 0) {
//如果当前挂起的任务正好是当前正在前台运行的任务,那么将第0个任务调度到前台
if (taskctl-&now &= taskctl-&running) {
taskctl-&now = 0;
farjmp(0, taskctl-&tasks[taskctl-&now]-&sel);
该函数的逻辑是,根据要挂起的任务,在整个任务数组中查找,找到其对应的数组下标,然后把后面的任务向前覆盖,这样的话,要移除的任务就在数组中就会被覆盖掉,从而实现将任务从数组中移除的目的。
需要注意的是,如果要挂起的任务,正好是当前正在前台运行的进程,那么ts==1,我们就把下标为0的任务调度到前台,并且把任务的数量也就是running的值减一,这样,处于数组最后的那个任务将不会有机会被调度。
任务挂起是实现了,那么当我们想重新把任务调度到前台时,该怎么做呢?我们可以利用现有的队列机制,回忆一下,一旦鼠标,键盘的事件发生时,我们会把硬件产生的数据加入到他们对应的队列中,然后在CMain主循环中,将队列中的数据取出来处理。同理,当我们挂起一个任务时,我们把挂起的任务对象放入到一个队列中,当想要重新调度这个对象时,我们往队列里发送一个数据,然后在主循环中对该队列进行检查,一旦发现队列中含有数据的话,那么就把队列中寄存的任务重新加入调度数组。代码修改如下,在golbal_define.c中:
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf,
struct TASK *task) {
fifo-&size =
fifo-&buf =
fifo-&free =
fifo-&flags = 0;
fifo-&p = 0;
fifo-&q = 0;
fifo-&task =
在初始化一个队列时,把一个任务对象添加进去,如果队列不需要寄存任务对象,那么把task设置为0就可以。
int fifo8_put(struct FIFO8 *fifo, unsigned char data) {
if (fifo == 0) {
return -1;
if (fifo-&free ==0) {
fifo-&flags |= FLAGS_OVERRUN;
return -1;
fifo-&buf[fifo-&p] =
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);
当队列中有数据加入时,顺便查看该队列是否寄存着一个任务对象,如果是,那么把该任务对象加入调度数组。
由于timer.c中,对计时器的运行需要使用到队列,既然队列的数据结构有变动,因此timer.c中,需要做一点小改动:
static struct TIMERCTL
extern struct TIMER *task_
init_pit(void) {
io_out8(PIT_CTRL, 0x34);
io_out8(PIT_CNT0, 0x9c);
io_out8(PIT_CNT0, 0x2e);
timerctl.count = 0;
for (i = 0; i & MAX_TIMER; i++) {
timerctl.timer[i].flags = 0; //not used
timerctl.timer[i].fifo = 0;
上面的改动在于,把每个timer对象的fifo队列成员设置为0。
接下来的改动主要在主入口函数中:
void CMain(void) {
fifo8_init(&timerinfo, 8, timerbuf, 0);
fifo8_init(&keyinfo, 32, keybuf, 0);
task_a = task_init(memman);
keyinfo.task = task_a;
上面代码的逻辑是,先通过task_init得到CMain函数所对应的任务对象,并把该任务对象寄存在键盘事件列表中,也就是keyinfo.task = task_a;
void CMain(void) {
task_run(task_b);
int pos = 0;
int stop_task_A = 0;
else if (fifo8_status(&timerinfo) != 0) {
int i = fifo8_get(&timerinfo);
if (i == 10) {
showString(shtctl, sht_back, pos, 144, COL8_FFFFFF,
timer_settime(timer, 100);
if (pos & 40 && stop_task_A == 0) {
task_sleep(task_a);
上面代码的逻辑时,当CMain函数在主循环中,连续打印字符"A",当打印的字符超过5个时,通过task_sleep(task_a)把CMain进程挂起。这样的话,系统运行时,我们会发现原来是字符A和B 是同时打印到桌面上的,此时便只剩下字符B在继续打印了。
这里写图片描述
由于我们把task_A寄存到键盘队列,那么当我们点击键盘,于是键盘数据就会存储到键盘队列中,由于键盘队列存储了任务Ad的任务对象,那么此时他会把对应任务对象重新加入到调度队列中,由此字符A会从恢复打印状态,也就是说,打印字符A的进程重新获得了被调度的机会。
这里写图片描述
参看视频,可以获得更加生动的演示展示。
更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:
这里写图片描述《VxWorks学习笔记》----任务属性
时间: 09:05:50
&&&& 阅读:96
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&VxWorks任务区别于通用系统的两个特点:1)VxWorks任务与内核具有相同的权限,能够执行处理器支持的全部指令。2)所有任务和内核共享同一实地址空间,不同任务的数据没有任何保护机制。
1、&&任务控制块(WIND_TCB):系统调度器用来管理任务调度的一个数据结构,每个任务都与一个TCB相关联,主要包括任务ID,任务名称,任务优先级和任务上下文等(VxWorks系统中TCB不用包含内存地址空间)。任务的切换主要设计任务上下文的保存与恢复。
2、&&任务栈:每个任务都有独立的栈空间,栈用于任务的函数调用,分配自动变量和函数返回值。栈的位置和大小在任务控制块中记录(创建任务时指点栈的大小)。VxWorks支持独立的中断栈(在处理器体系和BSP支持的条件下),即所有ISP共享一个独立于任务栈的栈空间。当硬件体系不支持时,中断栈属于被中断任务栈空间的一部分。系统提供checkStack()用以函数检测栈的使用情况。
3、&&出错状态:ANSI C标准定义了一个全局整形变量errno,用以记录底层函数调用时最后一次出错的详细信息(每次调用出错就会重置errno)。在VxWorks中,每个任务和ISP都维护了一个errno的副本(任务的errno记录在TCB中,ISP的errno记录在中断栈中)。VxWorks库函数中定义errno高16bits为模块编号,低16bits为错误编号。用户程序可以使用该定义,也可以重新定义。
4、&&钩子函数:VxWorks系统允许任务添加和删除钩子函数,钩子函数在某个任务中被添加后,在所用任务***享。VxWorks允许的钩子函数分三种:
1)任务创建钩子,任务被创建时在任务入口函数之前被调用。
2)任务调度钩子,在调度程序选择新任务运行时被调度。
3)任务删除钩子,在任务被删除后被调用。
在VxWorks中允许添加多个钩子函数,当有多个钩子函数时,任务创建钩子函数和任务调度钩子函数按其添加的顺序调用,任务删除钩子函数按其***的相反顺序调用。任务创建和删除钩子在参数所指的任务上下文中执行,而任务调度钩子在内核上下文中运行,因此任务调度钩子只能调用可以在内核上下文中被调用的函数。
5、&&任务状态:实时系统中的任务有多种状态,系统运行过程中任务可在不同状态之间转换。VxWorks系统定义的任务基本状态有5种:
1)& 运行:任务获得CPU资源运行。
2)& 就绪:ready,任务只等待系统分配CPU资源。
3)& 阻塞:pended,任务因等待不可用的资源而被阻塞。
4)& 延迟:delayed,任务被延迟执行。
5)& 挂起:suspended,任务不能被执行。这种状态主要用于调试,挂起一个任务并不会禁止它的状态转换,只是调度程序会忽略该任务,任务得不到执行。
上述基本状态也可以形成组合。系统函数控制着任务的状态转换,处于任一状态的函数都可以被删除。任务的状态转换关系如图:
标签:&&&&&&&&&原文:http://blog.csdn.net/iot_hept/article/details/
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!

参考资料

 

随机推荐