操作系统中用来解决资源共享和进程同步的一种方法(带有阻塞任务的功能)。
顾名思义,它只有两种状态:
被占用了可以看作0状态;
未被占用可以看作1状态。
SemaphoreHandle_t xSemaphoreCreateBinary(void); //创建二值信号量
SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer );
//静态方式创建二值信号量,需用户指定信号量的地址空间
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore ); //释放信号量
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken);
//从中断中释放信号量,后一个参数的返回值表示是否有高优先级的任务已经就绪,
//如果有,则需要进行一次任务切换
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
//获取信号量,后一个参数为阻塞的超时时间
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken); //在中断中获取信号量
信号量的状态可以不仅仅为0和1,可以为自然数,它可以表示一些资源数大于1的情况。
子:
我们有一块内存空间,共有20个字节,可以用一个初值为20的计数信号量来管理,每使用一个空间,
信号量减1;每释放一个空间,信号量加1。此信号量代表可使用空间的有无。
------------------可以说二值信号量是计数值最大为1的计数信号量。----------------
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount ); //创建计数信号量,两个参数为:最大计数值、初始值
SemaphoreHandle_t xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount, StaticSemaphore_t * pxSemaphoreBuffer );
//以静态形式创建计数信号量,需用户指定信号量的地址空间
释放、获取信号量的函数与二值信号量相同。
注意:
使用计数信号量时,要将以下宏定义改为1:
#define configUSE_COUNTING_SEMAPHORES 1
临界区的保护更加严格,它一旦保护,其它中断、任务都不会被执行,只有当前任务执行完才能退出;
信号量的保护不那么严格,它只限制那些等待这个信号量的任务,而与这个信号量无关的任务或中断是
不受影响的。
定义:
高优先级的任务A,因为信号量S(或者其他资源)的关系,必须等到中等优先级的任务B,或者低等优先级的任务C执行完了,才能执行的异常现象。
如果任务B,C执行的时间很长,那么就会导致高优先级的A需要等待很长时间,导致高优先级的任务实
时性变差。
一般有两种方法:优先级天花板和优先级继承
优先级天花板:当低优先级任务C占用资源时,
把C的优先级提高到可能访问该资源的任务的最高优先级(称为该资源优先级天花板)。
优先级继承:当出现高优先级任务A需要等待低优先级任务C占用的资源时,
将C的优先级提高到与A一样(有多个任务等待时,提高到等待它占用资源的任务的最高优先级)。
区别:
优先级继承只在高优先级任务被阻塞时提高低优先级任务的优先级,
优先级天花板在低优先级任务获取资源时就提高了自己的优先级。
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ); //获取任务的优先级
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); //修改任务的优先级
举个子:
为了避免优先级反转,我们用优先级天花板方法:C任务取得信号量时,把C任务的优先级提高到与A
任务一样;释放信号量时,再把C任务的优先级修改为原来的即可。
是一种特殊的二值信号量,能避免优先级反转问题:
①它与二值信号量的功能差不多,可以实现资源的互斥访问;
②它自带了优先级继承功能,当互斥信号量已经被低优先级任务C获取,如果高优先级任务A需要等待这个信号量,会自动将任务C的优先级提高到与A相同。
SemaphoreHandle_t xSemaphoreCreateMutex( void )
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
//释放信号量、获取信号量的函数与之前讲过的计数信号量、二值信号量相同,函数内部会自动判断是否是互斥信号量,如果是,它会执行优先级继承相关的调整。
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore ); //释放信号量
BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore,
signed BaseType_t *pxHigherPriorityTaskWoken);
//从中断中释放信号量,后一个参数的返回值表示是否有高优先级的任务已经就绪,
//如果有,则需要进行一次任务切换
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );
//获取信号量,后一个参数为阻塞的超时时间
BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore,
BaseType_t *pxHigherPriorityTaskWoken); //在中断中获取信号量