嵌入式实时系统中的共享全局变量

嵌入式实时系统中的共享全局变量


C语言的程序员为了方便,经常会不顾这个编码规范。全局变量有一些显而易见的好处:全局可见,内存地址固定,读写效率高。比起优点来,全局变量的槽点更多:1)学过面向对象语言的同学会更加谨慎的使用全局变量,这破坏了函数的封装性能,降低了函数的可移植性。2)使代码可读性差,大型程序里面简直是灾难 3)生存期长,会占用较多的内存单元。

嵌入式实时系统中需要注意的全局变量

举个例子
u8 Seconds;
u8 Minutes;
u8 Hours;
void TimeOfDay(void *p_arg)
{
(void)p_arg;
OS_ERR err;

        while (DEF_TRUE) {                                          /* Task body, always written as an infinite loop.       */
    
    OSTimeDlyHMSM(0, 0, 1, 0,
              OS_OPT_TIME_HMSM_STRICT,
              &err);
    Seconds++;
            if(Seconds > 59)
            {
                Seconds = 0;
                Minutes++;
                if(Minutes > 59)
                {
                    Minutes = 0;
                    Hours++;
                }
                if(Hours > 23)
                {
                    Hours = 0;
                }
            }
}

}
假如在模块执行完Minutes = 0;这一行代码时,一个中断发生了,并使得一个具有比void TimeOfDay(void *p_arg)更高优先级的任务进入了就绪表,那么在中断结束返回后,TimeOfDay()就会被这个更高优先级的任务抢占而无法继续运行。一旦高优先级的任务想要从时钟模块中获取时间,那么由于中断前时钟模块的小时值没有更新,那么所读到的将会是一个与正确时间相差整整一个小时的错误值。
这里的时钟模块就是一个共享资源,在ucos中必须对此加以保护,保证对共享资源的独占访问。
参考资料:
转自博客园网友《ucos中需要注意的全局变量》

解决办法

1 增加临界段,在上述代码块两端增加临界段限制任务切换.
OS_ENTER_CRITICAL();

OS_EXIT_CRITICAL();

2.使用互斥信号量,保证两个任务互斥,计时任务运行时,获取时间被阻断。
OSMutexPost();
OSMutexPend();

3.使用消息邮箱
将Seconds ,Minutes,Hours 定义为地址连续的数据结构,通过消息邮箱发送给获取时间的任务。
INT8U OSMboxPost (OS_EVENT *pevent,
void *pmsg)
OSMboxPost 自带临界段,且指针传递耗时较短,提高了共享全局的安全性。

    S_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {                   /* See if any task pending on mailbox            */
                                                      /* Ready HPT waiting on event                    */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_MBOX, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* Find highest priority task ready to run       */
        return (OS_ERR_NONE);
    }
    if (pevent->OSEventPtr != (void *)0) {            /* Make sure mailbox doesn't already have a msg  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_MBOX_FULL);
    }
    pevent->OSEventPtr = pmsg;                        /* Place message in mailbox                      */
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);

只有当一轮计时完成,给获取时间的任务发送消息以后,才会获取时间的任务才会读取时间。

如果获取时间的任务频率较高and优先级较高,可以及时将时间读走,不会出现时间覆盖的情况。
如果不满足以上情况,邮箱指针指向的时间继续累加,计数过程中进入中断并执行任务切换,还可能出现所读到的是一个与正确时间相差整整一个小时的错误值。

4.使用消息队列

为保证数据的连续性,不遗漏数据,可以使用消息队列。
将不同时刻的数据存放在不同的内存区,循环存放,每次数据都放入消息队列中。
INT8U OSQPost (OS_EVENT *pevent,
void *pmsg)存入数据。

使用void *OSQPend (OS_EVENT *pevent,
INT32U timeout,
INT8U *perr)读取最先存入的消息。

INT8U OSQPostFront (OS_EVENT *pevent,
void *pmsg)存入数据。
使用void *OSQPend (OS_EVENT *pevent,
INT32U timeout,
INT8U *perr)读取最后存入的消息。
使用消息队列,可以防止指针指向的数据正在累加时,进入任务切换。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值