在FreeRTOS中,任务进入阻塞状态通常是因为等待某个事件或资源。以下是常用的使任务进入阻塞态的API及其分类:
1. 任务延时
-
vTaskDelay(pdMS_TO_TICKS(ms))
将任务阻塞固定时间(相对延时,从调用时开始计算)。
示例:vTaskDelay(pdMS_TO_TICKS(100))
阻塞100毫秒。 -
vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(ms))
按固定频率阻塞任务(绝对时间,用于周期性任务)。
示例:实现精确的10ms周期任务。
2. 队列操作
-
xQueueReceive(xQueue, &buffer, pdMS_TO_TICKS(timeout))
从队列读取数据,若队列为空则阻塞,直到数据到达或超时。 -
xQueuePeek(xQueue, &buffer, pdMS_TO_TICKS(timeout))
查看队列数据(不移除),若队列为空则阻塞。 -
xQueueSend(xQueue, &data, pdMS_TO_TICKS(timeout))
向队列发送数据,若队列满则阻塞,直到空间可用或超时。
3. 信号量
xSemaphoreTake(xSemaphore, pdMS_TO_TICKS(timeout))
获取信号量,若信号量不可用则阻塞,常用于互斥量、二进制信号量。
4. 事件组
xEventGroupWaitBits(xEventGroup, uxBitsToWaitFor, xClearOnExit, xWaitForAllBits, pdMS_TO_TICKS(timeout))
等待事件组中的特定位被置位,满足条件前任务阻塞。
5. 任务通知
-
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(timeout))
等待任务通知(类似二进制信号量),通知值减1。 -
xTaskNotifyWait(0, ULONG_MAX, &ulValue, pdMS_TO_TICKS(timeout))
等待任务通知并获取通知值,支持更复杂场景。
6. 流缓冲区和消息缓冲区
-
xStreamBufferReceive(xStreamBuffer, &data, size, pdMS_TO_TICKS(timeout))
从流缓冲区读取数据,缓冲区为空时阻塞。 -
xMessageBufferReceive(xMessageBuffer, &msg, size, pdMS_TO_TICKS(timeout))
从消息缓冲区接收完整消息,无消息时阻塞。
关键区别
- 阻塞与挂起:阻塞是等待事件(自动恢复),挂起需手动恢复(
vTaskSuspend
/vTaskResume
)。 - 超时参数:上述API通常含
timeout
参数,设为portMAX_DELAY
会无限阻塞(需配置INCLUDE_vTaskSuspend
为1)。
示例场景
// 等待信号量,最多阻塞500ms
if (xSemaphoreTake(xSemaphore, pdMS_TO_TICKS(500)) == pdTRUE) {
// 成功获取信号量
}
// 从队列接收数据,无限阻塞
xQueueReceive(xQueue, &data, portMAX_DELAY);
这些API通过让任务等待特定条件,有效管理了CPU资源,适用于事件驱动或同步操作的设计。