【uTenux实验】信号量

    信号量(semaphore)是一个用来指示可用的资源并将可用资源的数量以数值的形式表示出来的对象。当使用一组资源时,信号量用来实现互斥控制和同步。uTenux提供了信号量出来的API,可以很方便地使用信号量。

        uTenux中,信号量包含一个资源计数(用来指示是否存在相应的资源以及资源的数量)和一个等待信号量的任务队列。

当一个任务返回m个资源时,信号量资源计数加m。当一个任务获得n个资源时,信号量资源计数减n。如果信号量资源的数量不够(进一步减少信号量计数可能使其值变成负数),则尝试获取资源的任务进入等待状态,直至下次有资源返回。等待信号量资源的任务被置入信号量队列。

1、创建信号量:IDsemid=tk_cre_sem(T_CSEM*pk_csem);

T_CSEM为信号量结构体,定义如下:

 

typedef    struct t_csem {
         VP                  exinf;                         /*扩展信息,OS不关心 */
         ATR                  sematr;                     /* 信号量属性*/
         INT                   isemcnt;                 /* 信号量初始计数 */
         INT                   maxsem;                 /* 最大信号量数目 */
         UB                  dsname[8];               /* Object name */
} T_CSEM;
信号量的属性可以用下面的表达式得到:

sematr:=(TA_TFIFO||TA_TPRI)|(TA_FIRST||TA_CNT)| [TA_DSNAME]

TA_TFIFO               任务按FIFO的顺序排队

TA_TPRI                任务按优先级顺序排队

TA_FIRST               队列中第一个任务最先获得资源

TA_CNT                请求越少的任务越先获得资源

TA_DSNAME         设定DS对象名

等待信号量的任务的排队顺序可以设置成TA_FIFOTA_TPRITA_FIRSTTA_CNT设定了获取资源的先后顺序

2、tk_sig_sem用来释放信号量

    提供一个释放信号量的数目即可。如果没有超过最大信号量计数,释放后,信号量技术增加这个数目。

3、tk_wai_sem用来申请信号量。

关于信号的量申请:

    如果一次需要获得多个信号量,但是信号量又不够。比如我需要3个信号量,但剩余的信号量只有1个。那么用tk_wai_sem申请信号量时候,不会改变信号量计数,然后开始等待其他信号量。

实验验证:

1、创建三个任务:任务ABC。其中任务A需要三个信号量,任务B需要4个信号量。任务A的优先级大于任务B。任务C为最低优先级的空闲任务。

2、创建任务后,先启动任务B,任务B先申请4个信号量。然后启动任务A

3、由于任务A的优先级高于任务B,任务B被中断,任务A开始执行。由于系统中没有可用信号量,任务A申请信号量失败 进入等待状态。

4、之后回到任务B,任务B释放四个信号量。此时,系统中有足够的信号量供任务A使用,任务A被唤醒。继续执行。

5、任务A执行一次之后进入休眠,任务B开始执行。任务B申请并获得4个信号量,完成LED反转。之后释放信号量进入休眠。

6、两个任务都进入等待状态,任务C开始执行。任务C是一个死循环。用于防止OS没有正在运行的任务而退出。

 

实验代码如下:

 

//本实验中,信号量代表开发板上的是个LED
//任务B需要4个信号量,控制LED同时亮灭
//任务A需要3个信号量,控制LED1、2、3同时亮灭

#include "SemSample.h"
#include <dev/ts_devdef.h>

void SemSampleTaskA(W stacd,VP exinf);
void SemSampleTaskB(W stacd,VP exinf);
void SemSampleTaskC(W stacd,VP exinf);
void SemSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID TaskID_C;
static ID semid;


ER SemSample(void)
{
  ER ercd = E_OK;
  T_CTSK ctsk;
  T_CSEM csem;
  
  ctsk.exinf = NULL;
  ctsk.task = SemSampleTaskA;
  ctsk.tskatr = TA_HLNG | TA_RNG0;
  ctsk.stksz = 512;
  ctsk.bufptr = NULL;
  ctsk.itskpri = 24;
  TaskID_A = tk_cre_tsk(&ctsk);
  if(TaskID_A< E_OK)
  {
    ercd = TaskID_A;
    return ercd;
  }
  
  ctsk.itskpri = 26;
  ctsk.stksz = 256;
  ctsk.task = SemSampleTaskB;
  TaskID_B = tk_cre_tsk(&ctsk);
  if(TaskID_B < E_OK)
  {
    ercd = TaskID_B;
    return ercd;
  }
  
  ctsk.itskpri = 28;
  ctsk.stksz = 256;
  ctsk.task = SemSampleTaskC;
  TaskID_C = tk_cre_tsk(&ctsk);
  if(TaskID_C < E_OK)
  {
    ercd = TaskID_C;
    return ercd;
  }
  
  //创建一个信号量
  csem.exinf = NULL;
  csem.isemcnt = 4;
  csem.maxsem = 4;
  csem.sematr = TA_TFIFO | TA_FIRST;
  semid = tk_cre_sem(&csem);
  if(semid < E_OK)
  {
    ercd = semid;
    return ercd;
  }
  SemSamplePutCnt();
  
  //启动任务B
  tk_sta_tsk(TaskID_B,5);

    return TRUE;
} 
 

void SemSampleTaskA(W stacd,VP exinf)
{
  ER ercd = E_OK;
  T_RSEM rsem;
  rsem = rsem;
  while(1)
  {
    tm_putstring((UB*)"任务A开始申请3个信号量
");
    SemSamplePutCnt();
    ercd = tk_wai_sem(semid,3,500);
    
    SemSamplePutCnt();
    if(ercd == E_OK)
    {
      LEDTog(LED1);
      LEDTog(LED2);
      LEDTog(LED3);
    }
    
    tm_putstring((UB*)"任务A开始释放3个信号量
");
    tk_sig_sem(semid,3);
    SemSamplePutCnt();
    
    tk_slp_tsk(500);
  }
 
}

void SemSampleTaskB(W stacd,VP exinf)
{
  ER ercd = E_OK;
  T_RSEM rsem;

  ercd = tk_sta_tsk(TaskID_C,0);
  
  SemSamplePutCnt();
  tk_wai_sem(semid,4,-1);
  ercd = tk_sta_tsk(TaskID_A,0);
  if(E_OK == ercd)
  {
    tm_putstring((UB*)"Start TaskA sucessfuly.
");
  }
  else
  {
    tm_putstring((UB*)"TaskB Failed start Task A.
");
  }
  tk_sig_sem(semid,4);
  //任务循环
  while(1)
  {
    //任务B需要4个信号量 

    SemSamplePutCnt();
    tm_putstring((UB*)"任务B开始申请4个信号量
");

    if(tk_wai_sem(semid,4,-1) == E_OK)
    {
      tm_putstring((UB*)"任务B成功获得4个信号量
");
      SemSamplePutCnt();
      LEDTog(LED1);
      LEDTog(LED2);
      LEDTog(LED3);
      LEDTog(LED4);
      if(tk_sig_sem(semid,4) == E_OK)
      {
        tm_putstring((UB*)"任务B成功释放4个信号量
");
      }
      else
      {
        tm_putstring((UB*)"任务B释放信号量失败
");
      }
    }
    else
    {
      tm_putstring((UB*)"任务B获取信号量失败
");
    }
    tk_slp_tsk(200);
   }
  
}

//防止任务全部休眠导致OS退出的空闲任务
void SemSampleTaskC(W stacd,VP exinf)
{
  B b;
  while(1)
  {
    tm_putstring((UB*)"this is in Task C
");
    for(b = 0;b<200;b++);
  }
}


void SemSamplePutCnt(void)
{
    B semcnt[10];
    T_RSEM rsem;

    tm_putstring((UB*)"当前的可用信号量数为: ");
    tk_ref_sem(semid, &rsem);
    ltostr(rsem.semcnt,semcnt,10,10);
    tm_putstring((UB*)semcnt);
    tm_putstring((UB*)"
");
}

 

实验时串口输出信息:

----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

当前的可用信号量数为: 4
当前的可用信号量数为: 4
任务A开始申请3个信号量
当前的可用信号量数为: 0
Start TaskA sucessfuly.
当前的可用信号量数为: 1
任务A开始释放3个信号量
当前的可用信号量数为: 4
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0
任务B成功释放4个信号量
this is in Task C
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0
任务B成功释放4个信号量
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0

原文地址:https://www.cnblogs.com/zyqgold/p/3163277.html