STM32F4X UCOSIII 互斥量

互斥量的概念

UCOSIII中的互斥量是一种特殊的信号量,它的本质也是一种信号量,不具备信息传递的功能。互斥量的主要作用是可以实现共享资源的互斥访问,提供优先级翻转机制。当一个任务持有互斥量时,除非该任务主动释放互斥量,否则其他任务都申请不到该互斥量。

互斥量的工作机制

洗手间问题

我们可以用一个实际的例子来说明一下互斥量的应用场景。假设有一个洗手间,洗手间里面有一把锁,假如现在游客A要进入洗手间,进入洗手间之后把锁锁上了,这时游客B也想进入洗手间,但是因为此时已经有人在洗手间,所以游客B无法进入,所以此时游客B只能在门外等,一直等待游客A上完洗手间之后,把锁打开,游客B才可以进入。
在上面的例子中,洗手间是共享资源,洗手间里面的锁是互斥量,游客A和游客B是两个任务。游客A上锁相当于是任务A申请互斥量,游客B等待相当于是任务B阻塞,游客A打开锁相当于是任务A解锁。

互斥量优先级继承

互斥量跟信号量非常类似,但是互斥量比信号量多了一个优先级继承的机制,下面可以通过一个例子来进行说明。

没有优先级继承

假设系统中有3个任务,分别是低优先级任务L,中优先级任务M和高优先级任务H。
在这里插入图片描述

  1. 任务L在使用共享资源,此时任务H被唤醒,开始执行,但是任务L还没释放共享资源。
  2. 任务H也要使用共享资源,但是任务L还没释放,所以任务H在阻塞等待。
  3. 任务M被唤醒,任务M优先级比任务L要高,任务M被执行,任务L还没有释放资源
  4. 任务M执行完毕,归还CPU资源,任务L继续执行
  5. 任务L执行完毕,释放资源,此时任务H获取资源,开始执行。
    从上面的例子可以看到,任务H是高优先级任务,但是等待时间过长,这对系统的实时性会造成一定的影响。

优先级继承

下面来看一下有优先级继承的效果,同样地也是假设系统中有3个任务,分别是低优先级任务L,中优先级任务M和高优先级任务H。
在这里插入图片描述

  1. 任务L在使用共享资源,此时任务H被唤醒,开始执行,但是任务L还没释放共享资源。
  2. 任务H也要使用共享资源,但是任务L还没释放,此时因为互斥量的优先级继承机制,任务L的优先级会被临时提升到跟任务H相同的优先级。
  3. 任务M被唤醒,但是因为任务M的优先级要比任务L的低,所以任务M处于就绪状态,没有被执行。
  4. 任务L运行完毕,释放资源,此时任务L的优先级会变成原来的优先级,任务H获取资源,开始运行。
  5. 任务H运行完成,释放资源,任务M开始运行。
  6. 任务M运行完毕,系统正常运行,按照设定好的优先级运行。
    可以看到,当使用互斥量时,任务L的优先级会被临时提高,这样就可以保证一些高优先级的任务能够尽快运行,尽可能提高系统的实时性。

UCOSIII互斥量API

互斥量创建函数

/*
	* p_mutex:互斥量对象
	* p_name:互斥量名字
	* p_err:错误代码
*/
void  OSMutexCreate (OS_MUTEX  *p_mutex,
                     CPU_CHAR  *p_name,
                     OS_ERR    *p_err)

互斥量删除函数

/*
	* p_mutex:要删除的互斥量对象
	* opt:用户选项
	* p_err:错误代码
返回值: 等于0:删除成功
	   大于0:互斥量上有等待的任务
*/
OS_OBJ_QTY  OSMutexDel (OS_MUTEX  *p_mutex,
                        OS_OPT     opt,
                        OS_ERR    *p_err)

其中opt可以选择OS_OPT_DEL_NO_PEND和OS_OPT_DEL_ALWAYS。

  • OS_OPT_DEL_NO_PEND:删除互斥量如果该互斥量上有挂起的任务,则等待挂起的任务恢复才删除。

  • OS_OPT_DEL_ALWAYS:不管该互斥量上是否有挂起的任务,直接删除互斥量

互斥量申请函数

/*
	* p_mutex:互斥量对象
	* timeout:超时时间
	* opt:用户选项
	* p_ts:时间戳
	* p_err:错误代码
*/
void  OSMutexPend (OS_MUTEX  *p_mutex,
                   OS_TICK    timeout,
                   OS_OPT     opt,
                   CPU_TS    *p_ts,
                   OS_ERR    *p_err)

opt选项可以选择OS_OPT_PEND_BLOCKING、OS_OPT_PEND_NON_BLOCKING

  • OS_OPT_PEND_BLOCKING:阻塞等待互斥量。
  • OS_OPT_PEND_NON_BLOCKING:不阻塞等待互斥量,如果任务等待时间超过设定的超时时间,任务会恢复并返回一个错误代码。

互斥量释放函数

/*
	* p_mutex:互斥量对象
	* opt:用户选项
	* p_err:错误代码
*/
void  OSMutexPost (OS_MUTEX  *p_mutex,
                   OS_OPT     opt,
                   OS_ERR    *p_err)

opt选项可以选择OS_OPT_POST_NONE和OS_OPT_POST_NO_SCHED。

  • OS_OPT_POST_NONE:释放互斥量不任何操作
  • OS_OPT_POST_NO_SCHED:释放互斥量的同时不进行调度

UCOSIII 互斥量例程

/*
*********************************************************************************************************
*                                              EXAMPLE CODE
*
*                             (c) Copyright 2013; Micrium, Inc.; Weston, FL
*
*                   All rights reserved.  Protected by international copyright laws.
*                   Knowledge of the source code may not be used to write a similar
*                   product.  This file may only be used in accordance with a license
*                   and should not be redistributed in any way.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                            EXAMPLE CODE
*
*                                       IAR Development Kits
*                                              on the
*
*                                    STM32F429II-SK KICKSTART KIT
*
* Filename      : app.c
* Version       : V1.00
* Programmer(s) : YS
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/

#include  <includes.h>

/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

                                                                /* ----------------- APPLICATION GLOBALS -------------- */
static  OS_TCB   AppTaskStartTCB;
static  CPU_STK  AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];

#define APPTASK1NAME    "App Task1"
#define APP_TASK1_PRIO          3   
#define APP_TASK1_STK_SIZE 1024
static OS_TCB AppTask1TCB;
static void  AppTask1  (void *p_arg);
static CPU_STK AppTask1Stk[APP_TASK1_STK_SIZE];

#define APPTASK2NAME    "App Task2"
#define APP_TASK2_PRIO          4   
#define APP_TASK2_STK_SIZE 1024
static OS_TCB AppTask2TCB;
static void  AppTask2  (void *p_arg);
static CPU_STK AppTask2Stk[APP_TASK2_STK_SIZE];

#define APPTASK3NAME    "App Task3"
#define APP_TASK3_PRIO          5   
#define APP_TASK3_STK_SIZE 1024
static OS_TCB AppTask3TCB;
static void  AppTask3  (void *p_arg);
static CPU_STK AppTask3Stk[APP_TASK3_STK_SIZE];

static OS_MUTEX  mutex;

/*
*********************************************************************************************************
*                                         FUNCTION PROTOTYPES
*********************************************************************************************************
*/

static  void  AppTaskStart          (void     *p_arg);


/*
*********************************************************************************************************
*                                                main()
*
* Description : This is the standard entry point for C code.  It is assumed that your code will call
*               main() once you have performed all necessary initialization.
*
* Arguments   : none
*
* Returns     : none
*********************************************************************************************************
*/

int main(void)
{

    OS_ERR  err;


    OSInit(&err);                                               /* Init uC/OS-III.                                      */
   
    OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,              /* Create the start task                                */
                 (CPU_CHAR     *)"App Task Start",
                 (OS_TASK_PTR   )AppTaskStart,
                 (void         *)0u,
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO,
                 (CPU_STK      *)&AppTaskStartStk[0u],
                 (CPU_STK_SIZE  )AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE / 10u],
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,
                 (OS_MSG_QTY    )0u,
                 (OS_TICK       )0u,
                 (void         *)0u,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);

    OSStart(&err);                                              /* Start multitasking (i.e. give control to uC/OS-III). */


}


/*
*********************************************************************************************************
*                                          STARTUP TASK
*
* Description : This is an example of a startup task.  As mentioned in the book's text, you MUST
*               initialize the ticker only once multitasking has started.
*
* Arguments   : p_arg   is the argument passed to 'AppTaskStart()' by 'OSTaskCreate()'.
*
* Returns     : none
*
* Notes       : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
*                  used.  The compiler should not generate any code for this statement.
*********************************************************************************************************
*/

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


   (void)p_arg;

    BSP_Init();                      
    CPU_Init();                                                 /* Initialize the uC/CPU services                       */

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */
    cnts         = cpu_clk_freq                                 /* Determine nbr SysTick increments                     */
                 / (CPU_INT32U)OSCfg_TickRate_Hz;

    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

    Mem_Init();                                                 /* Initialize memory managment module                   */
    Math_Init();                                                /* Initialize mathematical module                       */


#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif


#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
    App_SerialInit();                                           /* Initialize Serial communication for application ...  */
#endif
	

	OSTaskCreate((OS_TCB     *)&AppTask1TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK1NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask1, // 线程入口函数
			 (void       *) "TASK1", // 线程参数
			 (OS_PRIO     ) APP_TASK1_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask1Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 5u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK1NAME);
	else
		printf("%s Create Error\r\n",APPTASK1NAME);
	
			 
	OSTaskCreate((OS_TCB     *)&AppTask2TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK2NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask2, // 线程入口函数
			 (void       *) "TASK2", // 线程参数
			 (OS_PRIO     ) APP_TASK2_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask2Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 5u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK2NAME);
	else
		printf("%s Create Error\r\n",APPTASK2NAME);
		

	OSTaskCreate((OS_TCB     *)&AppTask3TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK3NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask3, // 线程入口函数
			 (void       *) "TASK3", // 线程参数
			 (OS_PRIO     ) APP_TASK3_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask3Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK3_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK3_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 5u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK3NAME);
	else
		printf("%s Create Error\r\n",APPTASK3NAME);
	
	
	OSMutexCreate(&mutex,"mutex",&err);
	if(OS_ERR_NONE == err)
		printf("Create Mutex Success\r\n");
	else
		printf("Create Mutex Error\r\n");

	
	OSTaskDel ( & AppTaskStartTCB, & err );		 

}

static void  AppTask1  (void *p_arg)
{
    OS_ERR      err;
	while(DEF_TRUE)
	{

		printf("APP1 获取互斥量 \r\n");

		OSMutexPend(&mutex,0,OS_OPT_PEND_BLOCKING,0,&err);
		printf("APP1 释放互斥量 \r\n");
		OSMutexPost(&mutex,OS_OPT_POST_NONE,&err);
		OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); // 1s运行一次
	}
	
}
static void  AppTask2  (void *p_arg)
{
    OS_ERR      err;
	while(DEF_TRUE)
	{
		printf("Task1 Runing  Task2 Arg %s\r\n",p_arg);
		OSTimeDly ( 200, OS_OPT_TIME_DLY, & err ); // 200ms运行一次
	}
	
}
static void  AppTask3  (void *p_arg)
{
    OS_ERR      err;
	static CPU_INT32U i;
	while(DEF_TRUE)
	{
		printf("APP3 获取互斥量 \r\n");
		OSMutexPend(&mutex,0,OS_OPT_PEND_BLOCKING,0,&err);
		
		for (i=0; i<600000; i++) //模拟低优先级任务占用信号量
		 {
		 OSSched();//发起任务调度
		 }
		 printf("APP3 释放互斥量 \r\n");

		OSMutexPost(&mutex,OS_OPT_POST_NONE,&err);
		OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); // 1s运行一次
	}
	
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值