FreeRTOS 的对称多处理 (SMP)
FreeRTOS 内核中的 SMP 支持可使一个 FreeRTOS FreeRTOS 内核实例在多个相同的处理器内核上调度任务。
这些内核架构必须相同,并共享相同的内存。
本页面包含:
FreeRTOS 和 SMP 入门指南
最简单的入门方法是使用以下预配置
的示例项目之一:
修改应用程序以使用 FreeRTOS SMP 功能
FreeRTOS API 单核和 SMP 版本之间基本上保持相同,除了
以下特定 API。因此,为尽量减少或不增加任何工作量,应同时编译 FreeRTOS 单核
与 SMP 版本。但是,
一些适用于单核应用的设计假设可能不适用于多核应用,
因此可能会存在一些功能问题。
其中一个常见的假定是,在较高优先级的任务正在运行时,
较低优先级的任务无法运行。虽然这在单核上是正确的,但并不适用于多核,
因为多个任务可以
同时运行。如果应用程序依赖于相对任务优先级来提供
相互排斥,则可能在多核环境中观察到意想不到的结果。
应用程序编写者有以下几个选择来解决这一问题:
- 最好的选择是更新应用程序,使其不依赖于任务优先级,
而是使用同步基元。
- 另一个选择是
使用
vTaskCoreAffinitySet
API 将所有不能同时运行的任务固定到一个内核。
- 第 3 个选则是将
configRUN_MULTIPLE_priority
定义为 0
,
这样可确保多个任务只有在具有相同优先级时
才会同时运行。请注意,这可能会导致利用率不足,
并使一些内核在可用于运行其他低优先级任务时处于空闲状态。
另一个常见的假定是, ISR 不能彼此或与其他任务同时运行。
这在多核环境中不再适用,应用程序编写者
需要在访问任务和 ISR 之间共享的数据时确保适当的互斥。可以在 ISR 中
使用宏 taskENTER_CRITICAL_FROM_ISR()
和 taskEXIT_CRITICAL_FROM_ISR()
,
并且可以在任务中使用宏 taskENTER_CRITICAL()
和 taskEXIT_CRITICAL()
,
以提供这种互斥。
SMP 特定 API
以下附加 API 可用于 FreeRTOS-SMP 内核:
xTaskCreateAffinitySet
BaseType_t xTaskCreateAffinitySet( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
UBaseType_t uxCoreAffinityMask,
TaskHandle_t * const pxCreatedTask );
此函数是 xTaskCreate 的扩展,
用于创建一个带有关联掩码的新任务,并将其添加到准备运行的任务列表中。
configUSE_CORE_AFFINITY
必须定义为 1,才可使用此函数。
参数:
xTaskCreateStaticAffinitySet
TaskHandle_t xTaskCreateStaticAffinitySet( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer,
UBaseType_t uxCoreAffinityMask );
此函数是 xTaskCreateStatic 的扩展,
用于创建一个带有关联掩码的新任务,并将其添加到准备运行的任务列表中。
configUSE_CORE_AFFINITY
必须定义为 1,才可使用此函数。
参数:
xTaskCreateRestrictedAffinitySet
BaseType_t xTaskCreateRestrictedAffinitySet( const TaskParameters_t * const pxTaskDefinition,
UBaseType_t uxCoreAffinityMask,
TaskHandle_t * pxCreatedTask );
此函数是
xTaskCreateRestricted 的扩展,
用于创建带有关联掩码的内存保护单元 (MPU) 受限任务,并将其添加到任务列表中
configUSE_CORE_AFFINITY
必须定义为 1,此函数
才可用。
参数:
xTaskCreateRestrictedStaticAffinitySet
BaseType_t xTaskCreateRestrictedStaticAffinitySet( const TaskParameters_t * const pxTaskDefinition,
UBaseType_t uxCoreAffinityMask,
TaskHandle_t * pxCreatedTask );
此函数是
xTaskCreateRestrictedStatic 的扩展,
并用于创建具有相关性掩码的内存保护单元(MPU)受限任务,并将其添加到准备运行的任务列表中。
configUSE_CORE_AFFINITY
必须定义为 1,此函数才可用
。
参数:
vTaskCoreAffinitySet
void vTaskCoreAffinitySet( const TaskHandle_t xTask, UBaseType_t uxCoreAffinityMask );
configUSE_CORE_AFFINITY
必须定义为 1
,才可使用此函数。
设置任务的内核关联掩码,即可以运行任务的内核。
参数:
用法示例:
void vAFunction( void )
{
TaskHandle_t xHandle;
UBaseType_t uxCoreAffinityMask;
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &( xHandle ) );
uxCoreAffinityMask = ( ( 1 << 0 ) | ( 1 << 2 ) );
vTaskCoreAffinitySet( xHandle, uxCoreAffinityMask );
}
vTaskCoreAffinityGet
UBaseType_t vTaskCoreAffinityGet( const TaskHandle_t xTask );
configUSE_CORE_AFFINITY
必须定义为 1
,才可使用此函数。
设置任务的内核关联掩码,即可以运行任务的内核。
参数:
返回:
用法示例:
TaskHandle_t xNetworkingTaskHandle;
void vAFunction( void )
{
TaskHandle_t xHandle;
UBaseType_t uxNetworkingCoreAffinityMask;
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &( xHandle ) );
uxNetworkingCoreAffinityMask = vTaskCoreAffinityGet( xNetworkingTaskHandle );
if( ( uxNetworkingCoreAffinityMask & ( 1 << 0 ) ) != 0 )
{
vTaskCoreAffinitySet( xHandle, ( 1 << 1 ) );
}
else
{
vTaskCoreAffinitySet( xHandle, ( 1 << 0 ) );
}
}
vTaskPreemptionDisable
void vTaskPreemptionDisable( const TaskHandle_t xTask );
configUSE_TASK_PREEMPTION_DISABLE
必须定义为 1
,才可使用此函数。
禁用抢占任务。
参数:
用法示例:
void vTaskCode( void *pvParameters )
{
( void ) pvParameters;
for( ;; )
{
vTaskPreemptionDisable( NULL );
vTaskPreemptionEnable( NULL );
}
}
vTaskPreemptionEnable
void vTaskPreemptionEnable( const TaskHandle_t xTask );
configUSE_TASK_PREEMPTION_DISABLE
必须定义为 1
,才可使用此函数。
启用抢占任务。
参数:
用法示例:
void vTaskCode( void *pvParameters )
{
( void ) pvParameters;
for( ;; )
{
vTaskPreemptionDisable( NULL );
vTaskPreemptionEnable( NULL );
}
}
SMP 特定钩子函数
空闲钩子函数
FreeRTOS SMP 内核有两种类型的闲置任务:
- 空闲任务:单核 FreeRTOS 应用程序中使用的标准空闲任务。
- 最小空闲任务:有 (
configNUMBER_OF_CORES - 1
) 个最小空闲任务,
这些任务在空闲内核上运行,不执行任何操作。
最小空闲任务可以选择性地调用应用程序定义的钩子
(或回调)函数,即最小空闲钩子。最小空闲任务以最低优先级运行,
只有在无较高优先级任务运行时,
这种空闲钩子函数才会运行。
只有 configUSE_MINIMAL_IDLE_HOOK
在 FreeRTOSConfig.h
中设置为 1
时,才会调用空闲钩子。设置后,应用程序必须为钩子函数
提供以下原型:
void vApplicationMinimalIdleHook( void );
只要最小空闲任务中的任何一个正在运行,
最小空闲任务就会重复调用最小空闲钩子函数。最重要的是,最小空闲钩子函数
不调用任何可能导致其阻塞的 API 函数。
SMP 特定配置选项
以下附加配置选项可用于 FreeRTOS-SMP 内核:
configNUMBER_OF_CORES
设置可用的处理器内核数。
configRUN_MULTIPLE_PRIORITIES
在单核 FreeRTOS 应用程序中,
如果存在能够运行的较高优先级任务,则较低优先级任务永远不会运行。 在 SMP FreeRTOS应用程序中,
RTOS 内核将运行与可用内核数量一样多的任务,在一个内核上运行优先级较低的任务的同时,
较高优先级的任务可能同时
在另一个内核上运行。 如果您的应用程序或库
为单核环境编写,并且因此对任务执行的顺序做出假设,
这可能会导致问题。 因此,提供 configRUN_MULTIPLE_PRIORITIES 来
控制此行为。
如果 configRUN_MULTIPLE_PRIORITIES
定义 0
,则多个任务
只有在具有相同优先级时才能同时运行,
保持这样的范例:如果存在能够运行的较高优先级任务,则较低优先级任务永远不会运行。
如果 configRUN_MULTIPLE_PRIORITIES
定义 1
,
则具有不同优先级的多个任务可以同时运行,因此,较高和较低优先级的任务可以同时
在不同的内核上运行。
configUSE_CORE_AFFINITY
应用程序编写者可以控制任务在哪些内核上运行。
如果 configUSE_CORE_AFFINITY
定义为 1
,则 vTaskCoreAffinitySet
可
控制任务在哪些内核上运行,vTaskCoreAffinityGet
可
用于查询任务在哪些内核上运行。 如果 configUSE_CORE_AFFINITY
为 0,
则 FreeRTOS 调度器可以在任何可用内核上自由运行任何任务。
configUSE_TASK_PREEMPTION_DISABLE
在单核 FreeRTOS 应用程序中,可以将 FreeRTOS 调度器配置为
抢占式或合作式——请参阅 configUSE_PREEMPTION 的定义。
在 SMP FreeRTOS 应用程序中,如果 configUSE_TASK_PREEMPTION_DISABLE
定义为 1
,
则可使用 vTaskPreemptionDisable
和 vTaskPreemptionEnable
API 函数将单个任务设置为抢占式或协作式。
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.