FreeRTOS 锁(信号量)
目录临界区critical sections互斥量Mutex优先级继承性code示例递归互斥量code示例二值信号量Binary Semaphore同步功能code示例计数信号量Counting Semaphore相关接口参考FreeRTOS中常见的用于同步/互斥访问的锁机制临界区critical sections该方法适用于极短code段的保护优先级高响应快但要注意保持时间尽可能短否则会影响实时性(调用时会关闭中断因而会影响系统响应时间)调用taskENTER_CRITICAL() 会全局禁用中断禁止上下文切换保持在运行状态直到退出临界区。适用于任务较短的临界区task执行时间较大会对中断时间产生不利影响void taskENTER_CRITICAL( void ); void taskEXIT_CRITICAL( void );可用于中断服务程序ISR的 taskENTER_CRITICAL() 版本但需要注意保存进入临界区时的中断掩码状态。UBaseType_t uxSavedInterruptStatus; uxSavedInterruptStatus taskENTER_CRITICAL_FROM_ISR(); /* 临界区 */ taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );互斥量Mutex该方式适用于互斥访问保护需要较长时间访问的资源。但使用时需要确保configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_MUTEXES 在FreeRTOSConfig.h 中设置为 1。优先级继承性互斥锁具有优先级继承机制如果另一个更高优先级任务B尝试获取与相对低的任务A相同的互斥锁则将暂时提高任务A的优先级与任务B优先级相同。该机制可以将优先级翻转危害降到最小。优先级翻转由于低优先级任务正在占用临界资源高优先级任务需要等低优先级任务使用完该资源后释放资源高优先级无法运行而低优先级任务可以运行的现象称为优先级翻转发生优先级翻转对操作系统是致命的危害会导致系统高优先级任务阻塞时间过长。如优先级为H M L的任务如果H在等L的临界资源释放优先级翻转时M被唤醒由于M会抢占L的CPU导致比M更高优先级的H等待更长时间互斥锁不能用在ISR中其特有的优先级继承机制只对任务起作用在中断的上下文环境中毫无意义。如某个task正在持互斥锁ISR中即使加了该锁也并不会因锁被持有而等待锁释放所以互斥锁用在ISR中毫无意义code示例SemaphoreHandle_t xSemaphore; /* 创建 mutex type semaphore */ xSemaphore xSemaphoreCreateMutex(); /* 正常task 中调用示例 */ if( xSemaphore ! NULL ) { /* See if we can obtain the semaphore. If the semaphore is not available wait 10 ticks to see if it becomes free. */ /* 超时等待 */ if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) pdTRUE ) { /* We were able to obtain the semaphore and can now access the shared resource. */ /* ... */ /* We have finished accessing the shared resource. Release the semaphore. */ xSemaphoreGive( xSemaphore ); } else { /* We could not obtain the semaphore and can therefore not access the shared resource safely. */ } } /* 删除互斥量 */ void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );递归互斥量递归互斥锁具有递归访问特性持有该互斥量的任务能够再次获得这个锁而不被挂起这个特性与一般的信号量有很大的不同在信号量中若已经持有该信号量再次获取信号量时会发生主动挂起任务最终形成死锁code示例/* 递归互斥量与普通互斥量使用方法类似 */ /* 创建mutex */ xMutex xSemaphoreCreateRecursiveMutex(); if( xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ) pdTRUE ) { /* 递归互斥量可以被同一个task持有多次但注意释放次数要与take次数相同 */ xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); xSemaphoreGiveRecursive( xMutex ); xSemaphoreGiveRecursive( xMutex ); } /* 删除互斥量 */ void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );二值信号量Binary Semaphore二值信号量是实现任务间通信的机制可以实现任务间同步或临界资源的互斥访问。与互斥量相比二值信号量没有优先级继承机制因而信号量更偏向于同步功能任务与任务间的同步或任务与中断的同步二值信号量是基于队列机制创建的信号量可将其看做一个消息队列该队列只能为空或满 即二值信号量只有0/1两种状态因此二值信号量没有累积性若Task A 连续多次释放最终信号量状态为1Task B take时只会认为有一次释放会错过多余的give因此在使用二值信号量做同步时尽可能避免上述情况若无法避免可使用计数信号量或 task notifications同步功能二值信号量的同步功能有时可以使用直达任务通知Task notifications来代替且比二进制信号量更快更节省内存与linux中的completion类似wait notify二值信号量用作同步功能时的操作流程信号量在创建后被置为空task a 获取信号量进入阻塞task b在某种条件发生后释放信号量task a从而得以获得信号量进入就绪态。如果task a 的优先级是最高的那么就会立即切换任务从而达到两个任务间的同步。同样的在ISR中释放信号量从而达到任务与中断间的同步。code示例#define LONG_TIME 0xffff #define TICKS_TO_WAIT 10 SemaphoreHandle_t xSemaphore NULL; /* Repetitive task. */ void vATask( void * pvParameters ) { /* We are using the semaphore for synchronisation so we create a binary semaphore rather than a mutex. We must make sure that the interrupt does not attempt to use the semaphore before it is created! */ xSemaphore xSemaphoreCreateBinary(); for( ;; ) { /* We want this task to run every 10 ticks of a timer. The semaphore was created before this task was started. Block waiting for the semaphore to become available. (等待ISR GIVE) */ if( xSemaphoreTake( xSemaphore, LONG_TIME ) pdTRUE ) { /* It is time to execute. */ ... /* We have finished our task. Return to the top of the loop where we will block on the semaphore until it is time to execute again. Note when using the semaphore for synchronisation with an ISR in this manner there is no need to give the semaphore back. */ } } } /* Timer ISR */ void vTimerISR( void * pvParameters ) { static unsigned char ucLocalTickCount 0; BaseType_t xHigherPriorityTaskWoken pdFALSE; /* A timer tick has occurred. */ ... Do other time functions. /* Is it time for vATask() to run? */ xHigherPriorityTaskWoken pdFALSE; ucLocalTickCount; if( ucLocalTickCount TICKS_TO_WAIT ) { /* Unblock the task by releasing the semaphore. */ xSemaphoreGiveFromISR( xSemaphore, xHigherPriorityTaskWoken ); /* Reset the count so we release the semaphore again in 10 ticks time. */ ucLocalTickCount 0; } /* Yield if xHigherPriorityTaskWoken is true. The actual macro used here is port specific. */ portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); }计数信号量Counting Semaphore计数信号量可被认为队列长度大于1的任务。与二值信号量一样当任务或中断释放一个信号量信号量的计数值会加1该值表示还有多个事件没被处理即可以不阻塞地take的次数也可以理解为系统中可用的资源数目。计数信号量可以用于资源管理允许多个任务同时访问共享资源但会限制任务的最大数目。相关接口/* 创建计数值为uxMaxCount的计数信号量 */ /* uxInitialCount: 创建信号量时分配给信号量的计数值 */ SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount); /* 返回信号量的计数值该接口也可以用于二值信号量但返回值只有0,1 */ UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );参考FreeRTOS 文档 - FreeRTOS™FreeRTOS内核实现与应用开发实战
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2433888.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!