欢迎光临
梦想从学习开始!

动手写简单的嵌入式操作系统二| 小熊测试

本文主要介绍 动手写简单的嵌入式操作系统二| 小熊测试,小熊希望对大家的学习或者工作具有一定的参考学习价值,在测试领域有所提升和发展。

接下来需要完成任务间的同步和通信。   任务间同步,为什么需要任务间同步,比如对公共资源的访问,如果不同步,一个任务正在访问资源,另一个任务不知道这个资源正在被访问,也去访问了,这就出现问题了。还有就是任务再等待某一事件的触发,触发后才能运行。实现的一种同步方法就是信号量。何为信号量?举个简单的例子来说,就像是资源的标识,如停车位,当还有停车位时,车才可以停进来,但没有停车位时,外面的车就必须等待,等到有停车位时再进来。下面是一个信号量的简单实现,原理就是用一个全局变量代表可用的资源。当有资源时,这个变量加一,当这个变量为0时代表没有资源了,任务开始挂起,同时开始切换到其它任务。 /*当前信号量列表*/

OS_SEM Sem[MAX_SEM_NUM];   

/*

 * 创建信号量

*/

OS_SEM* OSSemCreate(int32 conuter)

{

     OS_CPU_SR  cpu_sr = 0;

     uint32  index;

    if (conuter < 0)

    {

       return (OS_SEM*)NULL;

    }

 

     OS_ENTER_CRITICAL();

    for(index=0;index<MAX_SEM_NUM;index++)

    {

      if(Sem[index]==-1)

      {

         Sem[index]=conuter;

         OS_EXIT_CRITICAL();

         return(Sem[index]);

      }

    }

 

   OS_EXIT_CRITICAL();

   return (OS_SEM*)NULL;

}

int8 OSSemDelete(OS_SEM* pSem)

{

 OS_CPU_SR  cpu_sr = 0;

 OS_ENTER_CRITICAL();

 /*当且仅当信号量计数为0的时候,才能释放该信号量*/

 if ((*pSem) != 0)

 {

  OS_EXIT_CRITICAL();

  return OS_Err;

 }

 else

 {

  (*pSem) = (OS_SEM)-1;

  OS_EXIT_CRITICAL();

  return OS_OK;

 }

}

/*这个是一个不完全精确的实现*/

/*申请信号量*/

/*其超时时间不会非常精确*/

int8 OSSemPend(OS_SEM* pSem,uint32 timeout)

{

 uint32  index;

 OS_CPU_SR  cpu_sr = 0;

 for (index = 0;index < timeout;index++)

 {

  OS_ENTER_CRITICAL();

  if ((*pSem) > 0)

  {

   (*pSem)–;

   OS_EXIT_CRITICAL();

   return OS_OK;/*获取到了信号量*/

  }

  else

  {

   /*等待一个时间片*/

   OS_EXIT_CRITICAL();

   OSTimeDly(1);

  }

 }

 

 return OS_Err;

}

/*不等待,立即返回是否信号量能否获取*/

int8 OSSemGet(OS_SEM* pSem)

{

 OS_CPU_SR  cpu_sr = 0;

 OS_ENTER_CRITICAL();

 if ((*pSem) > 0)

 {

  (*pSem)–;

  OS_EXIT_CRITICAL();

  return OS_OK;/*获取到了信号量*/

 }

 OS_EXIT_CRITICAL();

 return OS_Err;

}

/*释放(发送)一个信号量*/

int8 OSSemPost(OS_SEM* pSem)

{

 OS_CPU_SR  cpu_sr = 0;

 OS_ENTER_CRITICAL();

 (*pSem)++;

 OS_EXIT_CRITICAL();

 return OS_OK;

}

 信号量如何使用?如何使用信号量来进行同步?下面是一个简单的应用例子。   我们知道printf函数不可重入,在调用这个函数时,必须保证不能被其他任务占用。所以不同任务需要保持同步,当一个任务释放了信号量后另一个任务方可使用。 OS_SEM*   testSem;

void  task6(void * arg)

{

    testSem=OSSemCreate(1); //创建一个信号量

    while(1 )

    {

         OSSemPend(testSem, 0);

         printf("task 6  Running! 27");

         OSSemPost(testSem);

         OSTimeDly(100);/*100毫秒10个*/

    }

}

   任务间如何通讯呢?可以用消息队列来实现。为什么要用消息队列?   消息被发送到队列中。“消息队列”是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传它。   下面是一个简单的实现,很容易看懂 /*用于对于的标记消息队列是否使用*/

uint8 MsgQueueFlag[MAX_QUEUE_NUMBER];

/*实际的所有消息队列*/

OS_Q MsgQueue[MAX_QUEUE_NUMBER];

/*

 * 创建消息队列

*/

OS_Q* OSQCreate()

{

 OS_CPU_SR  cpu_sr = 0;

 uint32  index;

 OS_ENTER_CRITICAL();

 for(index=0;index<MAX_QUEUE_NUMBER;index++)

 {

  /*该消息队列未被使用*/

  if (MsgQueueFlag[index]==0)

  {

   MsgQueueFlag[index]=1;

   /*该队列首尾初始化*/

   MsgQueue[index].front=NULL;

   MsgQueue[index].rear=NULL;

   OS_EXIT_CRITICAL();

   return &(MsgQueue[index]);

  }

 }

 

 OS_EXIT_CRITICAL();

 return (OS_Q*)NULL;

}

/*

*删除消息队列

*/

int8 OSQDelate(OS_Q* q)

{

 OS_CPU_SR  cpu_sr = 0;

 

 OS_ENTER_CRITICAL();

 /*信号量不存在*/

 if (q == NULL)

 {

  OS_EXIT_CRITICAL();

  return OS_Err;

 }

 /*队列指针越界*/

 if ((( q-MsgQueue ) < 0)||(( q-MsgQueue ) > (MAX_QUEUE_NUMBER-1)))

 {

  OS_EXIT_CRITICAL();

  return OS_Err;

 }

 

 /*将标记位置0*/

 MsgQueueFlag[q-MsgQueue] = (uint8)0;

 OS_EXIT_CRITICAL();

 return OS_OK;

}

/*

*发送一个消息

*该函数可用在中断函数中

*/

int8 OSQPost(OS_Q* q,OS_MSG msg)

{

    OS_CPU_SR  cpu_sr = 0;

 

   OS_ENTER_CRITICAL();

 if (q == NULL)

 {

       OS_EXIT_CRITICAL();

      return OS_Err;

 }

 if ((( q-MsgQueue ) < 0)||(( q-MsgQueue ) > (MAX_QUEUE_NUMBER-1)))

 {

      OS_EXIT_CRITICAL();

      return OS_Err;

 }

 if((q->rear+1)%MAX_MSG_NUMBER==q->front)

 {

      OS_EXIT_CRITICAL();

      return OS_Err;

 }

 else

 {

      q->msgQueue[q->rear]=msg;

      q->rear=(q->rear+1)%MAX_MSG_NUMBER;

      OS_EXIT_CRITICAL();

      return OS_OK;

 }

}

/*

*在有限时间片内等待一个消息

*该函数不能用在中断函数中,也不能在关中断的地方运行

*/

OS_MSG OSQPend(OS_Q *q, uint32 timeout)

{

 uint32  index;

 uint32  cpu_sr = 0;

 OS_MSG  msg;

 for (index = 0;index < timeout+1;index++)

 {

  OS_ENTER_CRITICAL();

  if (q->front==q->rear)

  {

   OS_EXIT_CRITICAL();

   OSTimeDly(1);

  }

  else

  {

   msg=q->msgQueue[q->front];

   /*消息个数满时自动从0开始重新计数*/

   q->front=(q->front+1)%MAX_MSG_NUMBER;

   OS_EXIT_CRITICAL();

   return msg;

  }

 }

 OS_EXIT_CRITICAL();

 return NULL ;

}

 

/*

*直接获取一个消息,可用在中断函数中

*/

OS_MSG OSQGet(OS_Q *q)

{

 OS_MSG msg;

 uint32  cpu_sr = 0;

 OS_ENTER_CRITICAL();

 if (q->front==q->rear)

 {

  OS_EXIT_CRITICAL();

  return NULL;

 }

 else

 {

  msg=q->msgQueue[q->front];

  q->front=(q->front+1)%MAX_MSG_NUMBER;

  OS_EXIT_CRITICAL();

  return msg;

 }

}

实时性和相关的优先级反转问题,   在实时领域,是个很关键的问题   首先说多任务,   任务就是让一段“流程”,一般都是一遍又一遍的循环运行(死循环)。   一次“流程”运行一遍之后,常常会等待一段时间,   自己休息休息,也让其他任务也运行一下,   这就是多任务并行。   在多任务的系统之中,实时性,就是让当前最高优先级的任务优先运行;   若当前最高优先级的任务不是当前正在运行的任务,那么就要给一个时机(时钟中断),   让高优先级的任务运行,正在运行的(低优先级)任务等下再运行。   这就是实时系统中的抢占调度。   实时操作系统的本质就是,   让当前最高优先级的任务以最快的速度运行!   (如果有同优先级的任务,则大家轮流运行)   由此看来,实时的多任务设计,难度在于:   要保证系统性能满足的需求,   在硬性保证高优先级任务在deadline之前运行完的同时   也要保证低优先级的任务顺利的完成自己的工作。   当然,这里就提出了优先级反转的问题了   典型情况如下:   高优先级的任务A要请求的资源被低优先级任务C所占用,   但是任务C的优先级比任务B的优先级低   于是任务B一直运行,比A低优先级的其他任务也一直能运行,   反而高优先级的任务A不能被运行了。   从实时性上讲,若高优先级在等待一个某个资源,
   那么为了保证高优先级任务能顺利运行,   则必须要让当前占用该资源的任务赶紧运行下去,直到把资源释放。   再让高优先级的任务来占用这个资源。   优先级反转在RTOS中是一个很深刻的课题,   目前还没有非常好的解决方案。   在这个问题上,目前业界比较典型的做法是VxWorks的做法   原理如下:   当任务A请求的资源被任务C所占用的时候   则将C的优先级提升到任务A的级别,让占有资源的任务先运行,   这样能在一定程度上解决优先级反转的问题。   但是这样做,事实上破坏了实时系统里面运行优先级的意义…   其他,有些商业RTOS也提出了一些解决方案   比如常见的极限优先级方案:   将使用资源的任务优先级提升到系统最高级别   使得任何使用该资源的任务都能快速通过   但是,对优先级意义的破坏性,比优先级继承方案更大!   接下来又有好多事情可以做了。比如可以细读一些其他的开源系统如ucos,freeRTOS,smallRTOS,RAW OS,keil RTX,RTTherad,uclinux,minix,linux以及一些比较著名的开源代码,虽然代码量很大,但是可以慢慢来,先看比较关注的某个模块是如何实现的。   一次看懂少部分,慢慢的就很有提高了。兴趣是最好的老师,多实践,看的再多也不如经手一遍。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小熊分享邦(www.xxfxb.com),希望大家能坚持软件测试之路,谢谢。

赞(0) 打赏
未经允许不得转载:小熊分享邦 » 动手写简单的嵌入式操作系统二| 小熊测试

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏