原子哥的任务启动方式分析

2019-07-21 03:41发布

先上代码(原子哥的“探索者-任务调度实验代码”):

//START 任务
//设置任务优先级
#define START_TASK_PRIO       10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE   64
//任务堆栈
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);
    
//LED0任务
//设置任务优先级
#define LED0_TASK_PRIO       7 
//设置任务堆栈大小
#define LED0_STK_SIZE       64
//任务堆栈
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任务函数
void led0_task(void *pdata);

//LED1任务
//设置任务优先级
#define LED1_TASK_PRIO       6 
//设置任务堆栈大小
#define LED1_STK_SIZE   64
//任务堆栈
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *pdata);

int main(void)

    delay_init(168);  //初始化延时函数
    LED_Init();        //初始化LED端口 

    OSInit();   
    OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务
    OSStart();
}

 //开始任务
void start_task(void *pdata)
{
     OS_CPU_SR cpu_sr=0;
     pdata = pdata; 
     OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断) 
    OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);           
    OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);   
    OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
    OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)


//LED0任务
void led0_task(void *pdata)
{
    while(1)
    {
    LED0=0;
    delay_ms(80);
    LED0=1;
    delay_ms(920);
    };
}

//LED1任务
void led1_task(void *pdata)
{  
    while(1)
    {
    LED1=0;
    delay_ms(300);
    LED1=1;
    delay_ms(300);
    };
}

主要逻辑:首先创建start_task任务,然后在start_task任务里面创建led0_task和led1_task任务。start_task任务优先级比led0_task和led1_task任务低。

我有以下几点看法

一, OS_ENTER_CRITICAL()与  OS_EXIT_CRITICAL()的使用。
1,这一对宏主要作用是用来保护临界代码,但是这里使用的时候并没有涉及到临界代码(操作系统函数内部的临界代码不算,因为它自己做了处理),并没有起到保护临界代码的作用,实际上起的作用是防止任务切换(阻止pendSV中断)。为什么呢?因为在调用OSTaskCreate创建led0_task和led1_task任务时,由于它们的优先级比start_task高,会进行任务切换,会触发pendSV中断异常,但是不会进入中断,因为OS_ENTER_CRITICAL()已经把中断关闭了。可以通过断点调试实验下。
2,当需要保护临界代码时,也不推荐使用这对宏,因为这一对宏主要是在ucos内核中使用,在用户程序中要谨慎使用(邵贝贝的《嵌入式实时操作系统ucos-II》中74页有说明),保护临界代码更好的方式是使用信号量。
二,我认为的更好的任务启动方式。
让启动任务
start_task的优先级比其他任务优先级高,这样在原子哥的代码的基础上,把OS_ENTER_CRITICAL()与  OS_EXIT_CRITICAL()这一对宏去掉就行了。我是参考vxworks操作系统的,这个系统内核会创建一个启动任务,这个任务的优先级是系统最高的,我们只需在启动任务创建自己的任务就行了。


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
taizonglai
1楼-- · 2019-07-21 09:31
你说的没错,可以将start_task的任务优先级调高,临界代码段保护最好的方式确实是信号量,但是有时候信号量也没用的,比如从外部SRAM中读取数据,最好不要被中断打断,这时候就可以使用OS_ENTER_CRITICAL()来关闭全局中断,数据读取完成后在打开中断。
磨剑
2楼-- · 2019-07-21 10:29
 精彩回答 2  元偷偷看……
taizonglai
3楼-- · 2019-07-21 12:39
回复【3楼】磨剑:
---------------------------------
我们推荐的使用SRAM的方式是动态内存管理,使用mymlloc()函数来申请的,在使用这个数组的时候,最好关闭中断,防止操作的时候被中断打断导致操作出错
磨剑
4楼-- · 2019-07-21 14:23
回复【4楼】zuozhongkai:
---------------------------------
嗯,明白了,我看了下代码,这里使用OS_ENTER_CRITICAL()处理临界区的访问。如果没有人在中断服务程序里面使用mymalloc(),信号量与OS_ENTER_CRITICAL()的效果是一样的;如果有人可能在中断服务程序里面使用mymalloc(),那么必须使用OS_ENTER_CRITICAL()。不过一般不会有人在中断服务程序干这个事吧

一周热门 更多>