• 【转载】嵌入式OS的栈


          有过嵌入式程序设计的程序员都知道,在创建一个新的任务时都要为其传入一个栈空间和栈的大小(有时),那么这个栈到底是用来干什么的呢?本文将带你找到答案。
    本文介绍的实验环境是Windows上移植的uCOSII,在VS.Net 2003中。
    一、栈首要的任务就是,存储当前任务的寄存器状态以便在任务切换时恢复到切换前的状态。
    这个功能是嵌入式的OS中栈的特有功能,其地址存放在任务的控制块TCB中。
    二、存放函数调用及局部变量。
           一个嵌入式系统中往往存在很多个任务,特定任务的栈只存放该任务调用的函数及局部变量,下面我们给出实验结果:
    //创建任务需要的栈空间
    int TaskStk[10][2048];    // Tasks stacks
    //创建任务
    OSTaskCreate(Task1, 0, &TaskStk[2][2047], 10);--------类似于task_define
    OSTaskCreate(Task2, 0, &TaskStk[3][2047], 9);
     
    void Task1(void * pParam)
    {
        while(1)
        {
            OS_ENTER_CRITICAL();   
            printf( "task1 is running\n");
            OS_EXIT_CRITICAL();
            OSTimeDly(5);
        }
    }
    void Task2(void * pParam)
    {
        int p = 10000;
        int *pp = &p;
        char str[100] = {0};
     
        while(1)
        {
            OS_ENTER_CRITICAL();   
            printf( "%s", "test 2\n");
            OS_EXIT_CRITICAL();
            OSTimeDly(10);
        }
    }
    上面创建了2个任务,它们的栈是连续分布的,每个栈的大小是2048 * 4 个字节。------(int 4个字节)
    运行时栈的实际地址为:
    &TaskStk[0][0]     0x0042e580
    &TaskStk[1][0]     0x00430580   
    &TaskStk[2][0]     0x00432580   
    &TaskStk[3][0]     0x00434580   
    于是,任务1的栈空间为0x00432580 –> 0x0043457f;
    任务2的栈空间为0x00434580 –> 0x0043657f;
    任务2中的局部变量int p = 10000;的地址为 0x00436568,正好落在了任务的栈中。靠近栈底0x0043657f的位置。
    任务2中的局部数据char str[100] = {0};的地址为0x004364f0,也正好落在了任务的栈中。
    以上足以说明了栈的存放局部变量的功能。
    三、更深层次的原因
           当一个任务获得CPU后,系统的寄存器就被设置为当前任务先前的寄存器状态,其中一个最要的寄存器ESP(始终指向栈顶)就指向了该任务的栈顶(栈的空间由我们创建时确定)。接下来的函数调用使用栈,通过ESP所有的操作都是在我们传入的空间上进行,函数内部的局部变量也是如此。
    四、栈溢出
           既然,这个栈是用来存放局部变量的,那就不可避免的要讨论栈溢出。我们申请一个较大的数组:char str[2048 * 4] = {0}; 这个空间显然已经超出了任务2的栈大小。而任务1和任务2的栈是连续的,那么,这个语句就覆盖了任务1 的栈,导致了任务无法正确的切换返回,并最终导致错误。
           但是,在真实的嵌入式环境中,这样的溢出会导致程序崩溃,但是,查找原因往往很难,因此,在嵌入式环境中使用局部变量时,要特别的注意。
       
    五、总结
           本文介绍了嵌入式OS中任务中栈的2个作用:任务切换和局部变量及调用。因为,稍有不慎很容易导致栈的溢出是整个系统崩溃,所以在使用布局的数据时,千万注意不要导致栈溢出,稍大一些数据空间可以使用动态申请或者声明为静态。

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cxyol/archive/2007/10/11/1820654.aspx

  • 相关阅读:
    设计模式之工厂模式
    Java内存区域与内存溢出异常
    Spark环境搭建
    Android获取蓝牙地址
    Intent和BroadcastReceiver
    Fragment初探
    Acticity的生命周期和启动模式
    Maven依赖,去哪儿找
    Spring-BeanDefinition
    Spring-BeanFactory体系介绍
  • 原文地址:https://www.cnblogs.com/hengfeng/p/1539648.html
Copyright © 2020-2023  润新知