一、互斥量简介
1、互斥量用于互锁,可以充当资源保护的令牌,当一个任务希望访问某个资源时,它必须先获取令牌,当任务使用完资源后,必须返还令牌,以便其他任务可以访问该资源。
2、互斥量一般用于临界资源保护。
3、用互斥量处理不同任务队临界资源的同步访问时,任务想要获取互斥量才能进行资源访问,如果一旦有任务成功获得了互斥量,则互斥量立即变为闭锁状态,此时其他任务会因为获取不到互斥量而不能访问这个资源,任务会根据用户自定义的等待时间进行等待,直到互斥量被持有的任务释放后,其他任务才能获取互斥量从而得到访问该临界资源,此时互斥量再次上锁,如此一来就可以确保每个时刻只有一个任务正在访问这个临界资源,保证了临界资源操作的安全性。
4、互斥量与递归互斥量
互斥量更适合于可能会引起优先级翻转的情况
递归互斥量更适用于任务可能会多次获取互斥量的情况下,这样可以避免同一任务多次递归持有而造成死锁的问题。
核心在于:谁上锁,就只能由谁开锁。
二、STM32CubeMX设置
1、配置RCC、USART1、时钟72M
2、配置SYS,将Timebase Source修改为除滴答定时器外的其他定时器。
3、初始化LED的两个引脚
4、开启FreeRTOS,v1与v2版本不同,一般选用v1即可
5、创建两个线程:任务LED1用作发送,LED2用作接收。
以上步骤可参考:STM32CubeMX学习笔记22—FreeRTOS(任务创建和删除)-CSDN博客
6、创建互斥量Mutex
在Mutexes
进行配置。
- Mutex Name:互斥量名称
-
Allocation:分配方式:
Dynamic
动态内存创建 - Conrol Block Name:控制块名称
7、生成代码
三、程序编程
1、创建一个互斥量:osMutexCreate
函数 | osMutexId osMutexCreate (const osMutexDef_t *mutex_def) |
---|---|
参数 | mutex_def:引用由osMutexDef定义的互斥量 |
返回值 | 成功返回互斥量ID,失败返回0 |
例:
osMutexId myMutex01Handle;
osMutexDef(myMutex01);
myMutex01Handle = osMutexCreate(osMutex(myMutex01));
2、创建一个递归互斥量:osRecursiveMutexCreate
用于创建一个递归互斥量,不是递归的互斥量由函数 osMutexCreate() 创建,且只能被同一个任务获取一次,如果同一个任务想再次获取则会失败。递归信号量则相反,它可以被同一个任务获取很多次,获取多少次就需要释放多少次。递归信号量与互斥量一样,都实现了优先级继承机制,可以减少优先级反转的反生。
函数 | osMutexId osRecursiveMutexCreate (const osMutexDef_t *mutex_def) |
---|---|
参数 | mutex_def:引用由osMutexDef定义的互斥量 |
返回值 | 成功返回互斥量ID,失败返回0 |
要想使用该函数必须在Config parameters
中把USE_RECURSIVE_MUTEXES
选择Enabled
来使能。
例:
osMutexId myMutex02Handle;
osMutexDef(myMutex02);
myMutex02Handle = osRecursiveMutexCreate(osMutex(myMutex02));
3、删除一个互斥量:osMutexDelete
用于删除一个互斥量。
函数 | osStatus osMutexDelete (osMutexId mutex_id) |
---|---|
参数 | mutex_id:互斥量ID |
返回值 | 错误码 |
例:
osMutexDelete(myMutex01Handle);
4、获取互斥量:osMutexWait
用于获取互斥量,但是递归互斥量并不能使用这个 API 函数获取。
例:
osMutexWait(myMutex01Handle,osWaitForever);//一直等待获取互斥量
5、获取递归互斥量:osRecursiveMutexWait
用于获取递归互斥量的宏,与互斥量的获取函数一样,osMutexWait()也是一个宏定义,它最终使用现有的队列机制,实际执行的函数是 xQueueTakeMutexRecursive() 。 获取递归互斥量之前必须由 osRecursiveMutexCreate() 这个函数创建。要注意的是该函数不能用于获取由函数 osMutexCreate() 创建的互斥量。
要想使用该函数必须在Config parameters
中把USE_RECURSIVE_MUTEXES
选择Enabled
来使能。
例:
osRecursiveMutexWait(myMutex02Handle,osWaitForever);//一直等待获取互斥量
6、释放互斥量:osMutexRelease
用于释放互斥量,但不能释放由函数 osRecursiveMutexCreate() 创建的递归互斥量。
函数 | osStatus osMutexRelease (osMutexId mutex_id) |
---|---|
参数 | mutex_id:互斥量ID |
返回值 |
错误码 |
例:
osMutexRelease(myMutex01Handle);
7、释放递归互斥量:osRecursiveMutexRelease
用于释放一个递归互斥量。已经获取递归互斥量的任务可以重复获取该递归互斥量。使用 osRecursiveMutexWait() 函数成功获取几次递归互斥量,就要使用 osRecursiveMutexRelease() 函数返还几次,在此之前递归互斥量都处于无效状态,别的任务就无法获取该递归互斥量。使用该函数接口时,只有已持有互斥量所有权的任务才能释放它,每释放一该递归互斥量,它的计数值就减 1。当该互斥量的计数值为 0 时(即持有任务已经释放所有的持有操作),互斥量则服务器托管网变为开锁状态,等待在该互斥量上的任务将被唤醒。如果任务的优先级被互斥量的优先级翻转机制临时提升,那么当互斥量被释放后,任务的优先级将恢复为原本设定的优先级。
函数 | osStatus osRecursiveMutexRelease (osMutexId mutex_id) |
---|---|
参数 | mutex_id:互斥量ID |
返回值 | 错误码 |
要想使用该函数必须在Con服务器托管网fig parameters
中把USE_RECURSIVE_MUTEXES
选择Enabled
来使能。
例:
osRecursiveMutexRelease(myMutex02Handle);
8、互斥量使用
如果两个线程都使用printf进行打印函数,如果同时打印可能导致资源抢夺,此时可以使用互斥量,将两个线程中打印的东西轮流进行打印,此时就不会出现资源抢夺问题。
LED1:
void LED1_Task1(void const * argument)
{
/* USER CODE BEGIN LED1_Task1 */
/* Infinite loop */
osStatus xReturn;
int i=0;
for(;;)
{
HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_5); //LED1状态每500s翻转一次
//获取互斥量 MuxSem,没获取到则一直等待 上锁
xReturn = osMutexWait(myMutex01Handle, /* 互斥量句柄 */
osWaitForever); /* 等待时间 */
if(osOK == xReturn)
{
//获取到互斥量,此时资源上锁,其他任务不得使用该资源(printf)
printf("LED1 run %d ",i++);
printf("LED1 run %d ",i++);
printf("LED1 run %d n",i++);
}
osMutexRelease(myMutex01Handle);//给出互斥量
osDelay(500);
}
/* USER CODE END LED1_Task1 */
}
LED2:
void LED2_Task03(void const * argument)
{
/* USER CODE BEGIN LED2_Task03 */
/* Infinite loop */
osStatus xReturn = osErrorValue;
int i=0;
for(;;)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5); //LED1状态每500s翻转一次
printf("LED2 run %d n",i++);
osDelay(100);
}
/* USER CODE END LED2_Task03 */
}
下载验证:
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
一.规则总述: -如果函数模板和普通函数都可以实现,优先调用普通服务器托管网函数 -可以通过空模板参数列表来强制调用函数模板 -函数模板也可以发生重载 -如果函数模板可以产生更好的匹配,优先调用函数模板 (1).如果函数模板和普通函数都可以实现,优先调用普通函…