一、freeRTOS任务死锁
FreeRTOS任务死锁是一种常见的问题,通常发生在多个任务相互等待对方释放资源的情况下。以下是一个简单的例子,用于说明FreeRTOS任务死锁的情况:
假设有两个任务Task1和Task2,它们需要共享两个资源ResourceA和ResourceB。每个任务都需要同时访问这两个资源才能完成它们的工作。如果两个任务同时试图获得ResourceA和ResourceB,但在尝试获取其中一个资源时被阻塞,那么就会导致死锁。
例如,Task1需要首先获得ResourceA,然后才能获得ResourceB,而Task2则需要首先获得ResourceB,然后才能获得ResourceA。如果Task1已经获取了ResourceA,但此时Task2正在占用ResourceB,那么Task1将等待Task2释放ResourceB才能继续执行。 同时, Task2也将等待Task1释放ResourceA才能继续执行, 这样两个任务都无法继续执行,进程就处于死锁状态了。
当发生任务死锁时,系统将永远无法正常运行,因为任务在等待其它任务释放资源,而该其它任务却也在等待某个资源,从而使得整个系统陷入僵局。要避免这种情况,我们需要仔细规划任务之间的资源使用,并确保任务只在确实需要使用资源时才进行请求。
二、以下是一个可能导致死锁的代码示例:
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#define TASK1_STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK2_STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK1_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define TASK2_PRIORITY ( tskIDLE_PRIORITY + 2 )
TaskHandle_t xTask1Handle, xTask2Handle;
SemaphoreHandle_t xSemaphoreA, xSemaphoreB;
void vTask1( void *pvParameters )
{
while( 1 )
{
/* 尝试获取ResourceA */
if( xSemaphoreTake( xSemaphoreA, portMAX_DELAY ) == pdPASS )
{
printf("Task1 has acquired ResourceA\n");
/* 尝试获取ResourceB */
if( xSemaphoreTake( xSemaphoreB, portMAX_DELAY ) == pdPASS )
{
printf("Task1 has acquired ResourceB\n");
/* 访问两个资源 */
printf("Task1 is accessing ResourceA and ResourceB...\n");
/* 释放资源 */
xSemaphoreGive( xSemaphoreB );
printf("Task1 has released ResourceB\n");
xSemaphoreGive( xSemaphoreA );
printf("Task1 has released ResourceA\n");
}
}
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
void vTask2( void *pvParameters )
{
while( 1 )
{
/* 尝试获取ResourceB */
if( xSemaphoreTake( xSemaphoreB, portMAX_DELAY ) == pdPASS )
{
printf("Task2 has acquired ResourceB\n");
/* 尝试获取ResourceA */
if( xSemaphoreTake( xSemaphoreA, portMAX_DELAY ) == pdPASS )
{
printf("Task2 has acquired ResourceA\n");
/* 访问两个资源 */
printf("Task2 is accessing ResourceA and ResourceB...\n");
/* 释放资源 */
xSemaphoreGive( xSemaphoreA );
printf("Task2 has released ResourceA\n");
xSemaphoreGive( xSemaphoreB );
printf("Task2 has released ResourceB\n");
}
}
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
void app_main( void )
{
xSemaphoreA = xSemaphoreCreateMutex();
xSemaphoreB = xSemaphoreCreateMutex();
xTaskCreate( vTask1, "Task1", TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, &xTask1Handle );
xTaskCreate( vTask2, "Task2", TASK2_STACK_SIZE, NULL, TASK2_PRIORITY, &xTask2Handle );
vTaskStartScheduler();
}
在这个示例代码中,Task1和Task2都需要同时获取ResourceA和ResourceB,但是它们以不同的顺序尝试获取这两个资源,这可能会导致死锁。因为如果Task1首先获得了ResourceA,而Task2首先获得了ResourceB,那么它们就会相互等待,导致死锁。
此外,示例代码中使用的是无限等待的方式获取资源,如果获取失败则一直等待,这样也很容易导致死锁的发生。
三、以下是一个示例代码,其中Task1和Task2都需要同时访问ResourceA和ResourceB,并且使用信号量来避免死锁。
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#define TASK1_STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK2_STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK1_PRIORITY ( tskIDLE_PRIORITY + 1 )
#define TASK2_PRIORITY ( tskIDLE_PRIORITY + 2 )
TaskHandle_t xTask1Handle, xTask2Handle;
SemaphoreHandle_t xSemaphoreA, xSemaphoreB;
void vTask1( void *pvParameters )
{
while( 1 )
{
/* 尝试同时获取ResourceA和ResourceB */
if( xSemaphoreTake( xSemaphoreA, pdMS_TO_TICKS( 1000 ) ) == pdPASS )
{
printf("Task1 has acquired ResourceA\n");
if( xSemaphoreTake( xSemaphoreB, pdMS_TO_TICKS( 1000 ) ) == pdPASS )
{
printf("Task1 has acquired ResourceB\n");
/* 访问两个资源 */
printf("Task1 is accessing ResourceA and ResourceB...\n");
/* 释放资源 */
xSemaphoreGive( xSemaphoreB );
printf("Task1 has released ResourceB\n");
xSemaphoreGive( xSemaphoreA );
printf("Task1 has released ResourceA\n");
}
else
{
/* 如果无法获取ResourceB,释放ResourceA并等待一段时间后重新尝试获取 */
xSemaphoreGive( xSemaphoreA );
printf("Task1 has released ResourceA\n");
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
else
{
/* 如果无法获取ResourceA,等待一段时间后重新尝试获取 */
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
void vTask2( void *pvParameters )
{
while( 1 )
{
/* 尝试同时获取ResourceB和ResourceA */
if( xSemaphoreTake( xSemaphoreB, pdMS_TO_TICKS( 1000 ) ) == pdPASS )
{
printf("Task2 has acquired ResourceB\n");
if( xSemaphoreTake( xSemaphoreA, pdMS_TO_TICKS( 1000 ) ) == pdPASS )
{
printf("Task2 has acquired ResourceA\n");
/* 访问两个资源 */
printf("Task2 is accessing ResourceA and ResourceB...\n");
/* 释放资源 */
xSemaphoreGive( xSemaphoreA );
printf("Task2 has released ResourceA\n");
xSemaphoreGive( xSemaphoreB );
printf("Task2 has released ResourceB\n");
}
else
{
/* 如果无法获取ResourceA,释放ResourceB并等待一段时间后重新尝试获取 */
xSemaphoreGive( xSemaphoreB );
printf("Task2 has released ResourceB\n");
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
else
{
/* 如果无法获取ResourceB,等待一段时间后重新尝试获取 */
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
void app_main( void )
{
xSemaphoreA = xSemaphoreCreateMutex();
xSemaphoreB = xSemaphoreCreateMutex();
xTaskCreate( vTask1, "Task1", TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, &xTask1Handle );
xTaskCreate( vTask2, "Task2", TASK2_STACK_SIZE, NULL, TASK2_PRIORITY, &xTask2Handle );
vTaskStartScheduler();
}
在该示例中,Task1和Task2在尝试获取两个资源时都会等待一定时间,如果在这段时间内无法成功获取两个资源,则会放弃当前的获取尝试并重新开始。由于使用了信号量,并且在获取资源时设置了最大等待时间,因此能够有效地避免死锁的发生。
标签:Task1,Task2,freeRTOS,ResourceA,任务,ResourceB,死锁,printf From: https://blog.51cto.com/u_15903730/6170256