• 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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    互斥量删除函数

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

    其中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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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  
    
    /*
    *********************************************************************************************************
    *                                            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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293

    在这里插入图片描述

  • 相关阅读:
    JWT 登录
    选择种植常规水稻?谋定·国稻种芯:为什么农民放弃杂交水稻
    虚拟摄像头之八: 从 Camera api2 角度看摄像头框架
    JS:轮播图终极版
    骨传导原理是什么,佩戴骨传导耳机的过程中对于耳道有无损害
    【Spring实现模拟银行转账】
    测试架构工程师需要具备哪些能力 ?
    一行代码让你的项目轻松使用Dapr
    C++游戏设计教程(4)—— 用颜色原理打印平面地图
    使用Selenium进行元素定位的全面指南
  • 原文地址:https://blog.csdn.net/hwx1546/article/details/133632657