信号量
计数量 | 二进制 | 互斥量 | 递归锁 | |
创建 | xSemCalc = xSemaphoreCreateCounting(10, 0);//计数最大值10,初始值0 | xSemUart = xSemaphoreCreateBinary(); | xSemUART = xSemaphoreCreateMutex(); | xSemUART = xSemaphoreCreateRecursiveMutex(); |
释放 | xSemaphoreGive(xSemCalc) ;//让信号量+1 | xSemaphoreGive(xSemUart) | xSemaphoreGive(xSemUart) | xSemaphoreGiveRecursive(xSemUART); |
获取 | xSemaphoreTake(xSemCalc,portMAX_DELAY) ;//让信号量-1 | xSemaphoreTake(xSemUart,portMAX_DELAY); | xSemaphoreTake(xSemUart,portMAX_DELAY); | (xSemaphoreTakeRecursive(xSemUART,portMAX_DELAY) |
总结 | 1,在main函数中创建信号量,并释放 2,使用时先take ,如果take不成功,处于阻塞状态,直到其他任务释放give了。 3,区别,新建信号量的函数不一样。 4,相同,获取和释放的函数一样。 | 二进制信号量,也称为二值信号量, 具有两种状态:可用和不可用。 任务可以尝试获取二进制信号量,如果信号量可用,则任务获取成功并继续执行; 如果信号量不可用,则任务会被阻塞,直到信号量变为可用。 二进制信号量主要用于控制任务之间的访问,但其并没有优先级继承机制。 因此,可以说二进制信号量是实现同步的更好选择, 而互斥锁则是实现简单互斥的更好选择。 在实际应用中,应根据具体的需求和场景来选择合适的同步机制 | 互斥量(也称为互斥锁)是一种特殊的二值信号量, 其主要特殊之处在于具有优先级继承机制。 这种机制能够暂 时地将互斥量持有者的优先级提升至所有等待此互斥量的任务所具有的最高优先级,有助于避免优先级翻转问题。 互斥量以锁的形式存在,用于确保在同一时间内只有一个任务可以访问共享资源,防止竞态条件等并发问题。 当一个任务需要访问共享资源时,它首先会尝试获取互斥量。 如果互斥量没有被其他任务占用,任务就能获取互斥量并继续执行; 否则,任务会被阻塞,直到互斥量可用。 此外,互斥量还支持嵌套,即一个任务在持有互斥量时,可以再次尝试获取互斥量。 | 谁持有,就由谁释放 递归上锁/解锁 递归锁是一种可重入的锁,这意味着同一个线程可以多次获取同一个递归锁而不会导致死锁。 |
示例代码 | 15_freertos_example_Semaphore | 15_freertos_example_Semaphore | 16_freertos_example_mutex | 19_freertos_example_mutex_recursive |
1,信号量与队列的区别,
队列可以在不同任务中传递信息,既可以把生产者的数据和生产者的状态告知给其他的任务。
而信号量只能传递不同任务的完成状态,无法传递数据。
2,涉及信号量(semaphore)的类型有:计数值(counting)、二进制(Binary)、互斥量(mutex)、递归锁(recursive)
二进制是特殊的计数值,计数最大值为1
二进制的缺陷1,存在优先级反转
二进制的缺陷2,存在别被人解锁风险
针对二进制的缺陷1,使用互斥量,通过优先级继承解决优先级反转问题。
针对二进制的缺陷2,使用递归锁,谁上锁,谁解锁,实现被别人解锁的风险。
3、互斥量是特殊的二进制,以锁的形式存在,具有优先级继承的特点,即低优先级的任务可以被锁后,高优先级的任务也被锁的情况下,低优先级任务可以解锁,并获得高优先级的优先级权,执行完成后,释放锁即优先级。这样保证了解锁后高优先级任务也能被运行。防止高优先级任务被锁后中优先级任务优先级反转执行。
4,在以上二进制上锁的过程中,存在解锁,当相同函数被任务A,B使用,当任务A上锁后,任务B也上锁会导致死锁。不能继续运行,引出了递归锁的概念。递归锁还具有谁上锁,谁解锁的特点,防止A上锁后被B解锁。
5,队列可以传递数据,信号量只能指示状态,数据传递可以用一个全局变量传递数据。
例子1:任务之间不带锁,导致的打印重叠
例子2:任务之间使用信号量-计数值,打印不重叠
例子3:任务之间使用信号量-二进值,打印不重叠
例子4:任务之间使用信号量-二进值,缺陷1,出现被别的任务释放锁情况
例子5:任务之间使用信号量-二进值,缺陷2,出现优先级反转问题
两次上锁,出现了死锁
解决方法使用互斥量
例子7:任务之间使用信号量-互斥值,使用优先级继承解决优先级反转问题
例子8:使用递归锁解决多次上锁,多次解锁,防止死锁
例子9:任务之间使用信号量-递归锁,使用递归锁决二进制锁被别人接掉的情况
二进制被别人解锁
互斥量被别人解锁
递归锁,谁上锁谁解锁