
| 생성 방식 | 함수 | 메모리 할당 | 사용 시기 | 장점 | 단점 |
|---|---|---|---|---|---|
| 동적 생성 | xTaskCreate() | Heap에서 자동 할당 | 일반적인 경우 | 사용이 간편함 | Heap 메모리 필요 |
| 정적 생성 | xTaskCreateStatic() | 사용자가 미리 할당 | 안전 중요 시스템 | 메모리 위치 제어 가능 | 코드가 복잡함 |
동적 생성은 편리하지만 Heap 단편화 위험이 있습니다. 안전 중요 시스템에서는 정적 생성을 권장합니다.
함수 원형:
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode, // Task 함수 포인터
const char * const pcName, // Task 이름 (디버깅용)
uint16_t usStackDepth, // Stack 크기 (words 단위)
void *pvParameters, // Task에 전달할 파라미터
UBaseType_t uxPriority, // 우선순위
TaskHandle_t *pvCreatedTask // Task 핸들 저장 (NULL 가능)
);
C 버전:
#include "FreeRTOS.h"
#include "task.h"
void vTaskExample(void *pvParameters) {
int count = 0;
while(1) {
printf("Task running: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
TaskHandle_t xTaskHandle = NULL;
BaseType_t xReturned;
// Task 동적 생성
xReturned = xTaskCreate(
vTaskExample, // Task 함수
"Example", // Task 이름
256, // Stack: 256 words = 1024 bytes
NULL, // 파라미터 없음
2, // 우선순위 2
&xTaskHandle // 핸들 저장
);
if(xReturned == pdPASS) {
printf("Task 생성 성공\n");
} else {
printf("Task 생성 실패 (메모리 부족)\n");
return 1;
}
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class Task {
protected:
TaskHandle_t taskHandle;
const char* taskName;
uint16_t stackSize;
UBaseType_t priority;
virtual void run() = 0;
static void taskEntry(void* pvParameters) {
Task* task = static_cast<Task*>(pvParameters);
task->run();
}
public:
Task(const char* name, uint16_t stack, UBaseType_t prio)
: taskName(name), stackSize(stack), priority(prio), taskHandle(nullptr) {}
bool create() {
BaseType_t xReturned = xTaskCreate(
taskEntry,
taskName,
stackSize,
this,
priority,
&taskHandle
);
if(xReturned == pdPASS) {
std::cout << "Task 생성 성공: " << taskName << std::endl;
return true;
} else {
std::cout << "Task 생성 실패: " << taskName << std::endl;
return false;
}
}
TaskHandle_t getHandle() const { return taskHandle; }
virtual ~Task() {}
};
class ExampleTask : public Task {
private:
int count;
public:
ExampleTask() : Task("Example", 256, 2), count(0) {}
void run() override {
while(1) {
std::cout << "Task running: " << count++ << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
int main(void) {
ExampleTask task;
if(task.create()) {
vTaskStartScheduler();
} else {
return 1;
}
while(1);
}
함수 원형:
TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode,
const char * const pcName,
uint32_t ulStackDepth,
void * pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer, // 미리 할당된 Stack 버퍼
StaticTask_t * const pxTaskBuffer // 미리 할당된 TCB 버퍼
);
정적 생성은 메모리를 사용자가 직접 관리하므로 Heap 단편화 없이 안전하게 Task를 생성할 수 있습니다.
C 버전:
#include "FreeRTOS.h"
#include "task.h"
// FreeRTOSConfig.h에 추가 필요
// #define configSUPPORT_STATIC_ALLOCATION 1
void vStaticTask(void *pvParameters) {
int count = 0;
while(1) {
printf("Static Task: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
// Task를 위한 Stack 버퍼 (정적 할당)
static StackType_t xTaskStack[256];
// Task Control Block 버퍼 (정적 할당)
static StaticTask_t xTaskBuffer;
TaskHandle_t xHandle;
// 정적 Task 생성
xHandle = xTaskCreateStatic(
vStaticTask, // Task 함수
"Static", // Task 이름
256, // Stack 크기
NULL, // 파라미터
2, // 우선순위
xTaskStack, // Stack 버퍼
&xTaskBuffer // TCB 버퍼
);
if(xHandle == NULL) {
printf("정적 Task 생성 실패\n");
return 1;
}
printf("정적 Task 생성 성공\n");
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class StaticTask : public Task {
private:
StackType_t taskStack[256];
StaticTask_t taskBuffer;
int count;
public:
StaticTask() : Task("Static", 256, 2), count(0) {}
bool createStatic() {
taskHandle = xTaskCreateStatic(
taskEntry,
taskName,
stackSize,
this,
priority,
taskStack,
&taskBuffer
);
if(taskHandle == nullptr) {
std::cout << "정적 Task 생성 실패" << std::endl;
return false;
}
std::cout << "정적 Task 생성 성공" << std::endl;
return true;
}
void run() override {
while(1) {
std::cout << "Static Task: " << count++ << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
int main(void) {
StaticTask task;
if(task.createStatic()) {
vTaskStartScheduler();
} else {
return 1;
}
while(1);
}
C 버전:
#include "FreeRTOS.h"
#include "task.h"
void check_heap_status(void) {
size_t freeHeap = xPortGetFreeHeapSize();
size_t minFreeHeap = xPortGetMinimumEverFreeHeapSize();
printf("현재 Free Heap: %zu bytes\n", freeHeap);
printf("최소 Free Heap: %zu bytes\n", minFreeHeap);
}
void vDynamicTask(void *pvParameters) {
while(1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vStaticTask(void *pvParameters) {
while(1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
printf("=== 초기 상태 ===\n");
check_heap_status();
// 동적 Task 생성
printf("\n=== 동적 Task 생성 ===\n");
xTaskCreate(vDynamicTask, "Dynamic", 256, NULL, 2, NULL);
check_heap_status();
// 정적 Task 생성
printf("\n=== 정적 Task 생성 ===\n");
static StackType_t xStack[256];
static StaticTask_t xTCB;
xTaskCreateStatic(vStaticTask, "Static", 256, NULL, 2, xStack, &xTCB);
check_heap_status(); // Heap 사용량 변화 없음
vTaskStartScheduler();
while(1);
}
출력 예시:
=== 초기 상태 ===
현재 Free Heap: 15360 bytes
최소 Free Heap: 15360 bytes
=== 동적 Task 생성 ===
현재 Free Heap: 14208 bytes (1152 bytes 감소)
최소 Free Heap: 14208 bytes
=== 정적 Task 생성 ===
현재 Free Heap: 14208 bytes (변화 없음)
최소 Free Heap: 14208 bytes
함수 원형:
void vTaskDelete(TaskHandle_t xTaskToDelete);
파라미터:
NULL: 자기 자신 삭제TaskHandle: 다른 Task 삭제Task를 삭제하면 해당 Task의 Stack과 TCB 메모리가 Idle Task에 의해 해제됩니다.
C 버전:
#include "FreeRTOS.h"
#include "task.h"
// 자기 자신을 삭제하는 Task
void vSelfDeleteTask(void *pvParameters) {
int count = 0;
while(1) {
printf("Self Delete Task: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
if(count >= 5) {
printf("Task 자기 자신 삭제\n");
vTaskDelete(NULL); // NULL = 자기 자신
}
}
// 이 코드는 실행되지 않음
printf("이 메시지는 출력되지 않음\n");
}
// 다른 Task를 삭제하는 Task
TaskHandle_t xWorkerHandle = NULL;
void vWorkerTask(void *pvParameters) {
while(1) {
printf("Worker Task 실행 중...\n");
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vControlTask(void *pvParameters) {
int count = 0;
while(1) {
printf("Control Task: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
if(count == 10 && xWorkerHandle != NULL) {
printf("Worker Task 삭제\n");
vTaskDelete(xWorkerHandle);
xWorkerHandle = NULL;
}
}
}
int main(void) {
// 자기 삭제 예제
xTaskCreate(vSelfDeleteTask, "SelfDelete", 128, NULL, 2, NULL);
// 다른 Task 삭제 예제
xTaskCreate(vWorkerTask, "Worker", 128, NULL, 2, &xWorkerHandle);
xTaskCreate(vControlTask, "Control", 128, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class SelfDeleteTask : public Task {
private:
int count;
public:
SelfDeleteTask() : Task("SelfDelete", 128, 2), count(0) {}
void run() override {
while(1) {
std::cout << "Self Delete Task: " << count++ << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
if(count >= 5) {
std::cout << "Task 자기 자신 삭제" << std::endl;
vTaskDelete(taskHandle);
return; // 안전하게 종료
}
}
}
};
class WorkerTask : public Task {
public:
WorkerTask() : Task("Worker", 128, 2) {}
void run() override {
while(1) {
std::cout << "Worker Task 실행 중..." << std::endl;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
};
class ControlTask : public Task {
private:
WorkerTask& worker;
int count;
public:
ControlTask(WorkerTask& w) : Task("Control", 128, 3), worker(w), count(0) {}
void run() override {
while(1) {
std::cout << "Control Task: " << count++ << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
if(count == 10) {
std::cout << "Worker Task 삭제" << std::endl;
vTaskDelete(worker.getHandle());
}
}
}
};
int main(void) {
SelfDeleteTask selfTask;
WorkerTask workerTask;
ControlTask controlTask(workerTask);
selfTask.create();
workerTask.create();
controlTask.create();
vTaskStartScheduler();
while(1);
}
C 버전:
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
SemaphoreHandle_t xMutex;
// 잘못된 예: Mutex를 잡고 있는 상태에서 삭제
void vBadTask(void *pvParameters) {
while(1) {
if(xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
printf("Mutex 획득\n");
// 위험! Mutex를 반환하지 않고 삭제
vTaskDelete(NULL);
// 실행되지 않음
xSemaphoreGive(xMutex);
}
}
}
// 올바른 예: 리소스 정리 후 삭제
void vGoodTask(void *pvParameters) {
int *dynamicData = (int*)pvPortMalloc(sizeof(int) * 10);
while(1) {
if(xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
// 작업 수행
// Mutex 반환
xSemaphoreGive(xMutex);
}
// 종료 조건 확인
if(should_terminate) {
// 리소스 정리
vPortFree(dynamicData);
// Task 삭제
vTaskDelete(NULL);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
주의사항 요약:
1. Mutex/Semaphore를 잡고 있는 상태에서 삭제 금지
2. 동적 할당한 메모리는 삭제 전에 해제
3. 다른 Task가 참조하는 핸들은 삭제 후 NULL로 설정
4. 삭제된 Task의 메모리는 Idle Task에서 회수됨
함수 원형:
void vTaskSuspend(TaskHandle_t xTaskToSuspend);
void vTaskResume(TaskHandle_t xTaskToResume);
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume);
Suspend된 Task는 스케줄러에서 제외되어 CPU 시간을 전혀 소비하지 않습니다.
C 버전:
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t xWorkerHandle;
void vWorkerTask(void *pvParameters) {
int count = 0;
while(1) {
printf("Worker Task 실행: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vControlTask(void *pvParameters) {
while(1) {
printf("Worker Task 일시정지\n");
vTaskSuspend(xWorkerHandle);
vTaskDelay(pdMS_TO_TICKS(3000));
printf("Worker Task 재개\n");
vTaskResume(xWorkerHandle);
vTaskDelay(pdMS_TO_TICKS(3000));
}
}
int main(void) {
xTaskCreate(vWorkerTask, "Worker", 128, NULL, 2, &xWorkerHandle);
xTaskCreate(vControlTask, "Control", 128, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class Task {
protected:
TaskHandle_t taskHandle;
const char* taskName;
uint16_t stackSize;
UBaseType_t priority;
virtual void run() = 0;
static void taskEntry(void* pvParameters) {
Task* task = static_cast<Task*>(pvParameters);
task->run();
}
public:
Task(const char* name, uint16_t stack, UBaseType_t prio)
: taskName(name), stackSize(stack), priority(prio), taskHandle(nullptr) {}
void create() {
xTaskCreate(taskEntry, taskName, stackSize, this, priority, &taskHandle);
}
void suspend() {
if(taskHandle != nullptr) {
vTaskSuspend(taskHandle);
}
}
void resume() {
if(taskHandle != nullptr) {
vTaskResume(taskHandle);
}
}
TaskHandle_t getHandle() const { return taskHandle; }
virtual ~Task() {}
};
class WorkerTask : public Task {
private:
int count;
public:
WorkerTask() : Task("Worker", 128, 2), count(0) {}
void run() override {
while(1) {
std::cout << "Worker Task 실행: " << count++ << std::endl;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
};
class ControlTask : public Task {
private:
WorkerTask& worker;
public:
ControlTask(WorkerTask& w) : Task("Control", 128, 3), worker(w) {}
void run() override {
while(1) {
std::cout << "Worker Task 일시정지" << std::endl;
worker.suspend();
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "Worker Task 재개" << std::endl;
worker.resume();
vTaskDelay(pdMS_TO_TICKS(3000));
}
}
};
int main(void) {
WorkerTask workerTask;
ControlTask controlTask(workerTask);
workerTask.create();
controlTask.create();
vTaskStartScheduler();
while(1);
}
C 버전:
void vSelfSuspendTask(void *pvParameters) {
int count = 0;
while(1) {
printf("Task 실행: %d\n", count++);
vTaskDelay(pdMS_TO_TICKS(1000));
if(count >= 5) {
printf("자기 자신 일시정지\n");
vTaskSuspend(NULL); // NULL = 자기 자신
// 다른 Task가 vTaskResume()을 호출할 때까지 대기
printf("재개됨!\n");
}
}
}
실행 결과:
Task 실행: 0
Task 실행: 1
Task 실행: 2
Task 실행: 3
Task 실행: 4
자기 자신 일시정지
(다른 Task가 Resume 호출 시)
재개됨!
Task 실행: 5
함수 원형:
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);
UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);
C 버전:
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t xTask1Handle;
TaskHandle_t xTask2Handle;
void vTask1(void *pvParameters) {
while(1) {
printf("[Task1] 우선순위: %d\n", uxTaskPriorityGet(NULL));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2(void *pvParameters) {
while(1) {
printf("[Task2] 우선순위: %d\n", uxTaskPriorityGet(NULL));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vControlTask(void *pvParameters) {
int count = 0;
while(1) {
count++;
if(count == 5) {
printf(">>> Task1 우선순위 상승 (1 → 4)\n");
vTaskPrioritySet(xTask1Handle, 4);
}
if(count == 10) {
printf(">>> Task1 우선순위 복구 (4 → 1)\n");
vTaskPrioritySet(xTask1Handle, 1);
}
if(count == 15) {
printf(">>> Task2 우선순위 상승 (2 → 5)\n");
vTaskPrioritySet(xTask2Handle, 5);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
xTaskCreate(vTask1, "Task1", 128, NULL, 1, &xTask1Handle);
xTaskCreate(vTask2, "Task2", 128, NULL, 2, &xTask2Handle);
xTaskCreate(vControlTask, "Control", 128, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class Task {
protected:
TaskHandle_t taskHandle;
const char* taskName;
uint16_t stackSize;
UBaseType_t priority;
virtual void run() = 0;
static void taskEntry(void* pvParameters) {
Task* task = static_cast<Task*>(pvParameters);
task->run();
}
public:
Task(const char* name, uint16_t stack, UBaseType_t prio)
: taskName(name), stackSize(stack), priority(prio), taskHandle(nullptr) {}
void create() {
xTaskCreate(taskEntry, taskName, stackSize, this, priority, &taskHandle);
}
void setPriority(UBaseType_t newPriority) {
if(taskHandle != nullptr) {
vTaskPrioritySet(taskHandle, newPriority);
priority = newPriority;
}
}
UBaseType_t getPriority() const {
if(taskHandle != nullptr) {
return uxTaskPriorityGet(taskHandle);
}
return 0;
}
TaskHandle_t getHandle() const { return taskHandle; }
virtual ~Task() {}
};
class WorkTask : public Task {
private:
int taskId;
public:
WorkTask(int id, const char* name, UBaseType_t prio)
: Task(name, 128, prio), taskId(id) {}
void run() override {
while(1) {
std::cout << "[Task" << taskId << "] 우선순위: "
<< getPriority() << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
class ControlTask : public Task {
private:
WorkTask& task1;
WorkTask& task2;
int count;
public:
ControlTask(WorkTask& t1, WorkTask& t2)
: Task("Control", 128, 3), task1(t1), task2(t2), count(0) {}
void run() override {
while(1) {
count++;
if(count == 5) {
std::cout << ">>> Task1 우선순위 상승 (1 → 4)" << std::endl;
task1.setPriority(4);
}
if(count == 10) {
std::cout << ">>> Task1 우선순위 복구 (4 → 1)" << std::endl;
task1.setPriority(1);
}
if(count == 15) {
std::cout << ">>> Task2 우선순위 상승 (2 → 5)" << std::endl;
task2.setPriority(5);
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
int main(void) {
WorkTask task1(1, "Task1", 1);
WorkTask task2(2, "Task2", 2);
ControlTask controlTask(task1, task2);
task1.create();
task2.create();
controlTask.create();
vTaskStartScheduler();
while(1);
}
긴급 모드 전환 예제:
C 버전:
typedef enum {
MODE_NORMAL,
MODE_EMERGENCY
} SystemMode;
SystemMode currentMode = MODE_NORMAL;
TaskHandle_t xSensorHandle;
void vSensorTask(void *pvParameters) {
while(1) {
read_sensor();
UBaseType_t priority = uxTaskPriorityGet(NULL);
printf("센서 Task 우선순위: %d\n", priority);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vEmergencyDetector(void *pvParameters) {
while(1) {
if(emergency_detected()) {
currentMode = MODE_EMERGENCY;
// 센서 Task를 최고 우선순위로
vTaskPrioritySet(xSensorHandle, configMAX_PRIORITIES - 1);
printf("긴급 모드: 센서 우선순위 상승\n");
} else if(currentMode == MODE_EMERGENCY) {
currentMode = MODE_NORMAL;
// 정상 우선순위로 복구
vTaskPrioritySet(xSensorHandle, 2);
printf("정상 모드: 센서 우선순위 복구\n");
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
함수 원형:
UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask);
High Water Mark는 Stack에서 사용되지 않은 최소 공간을 의미합니다. 값이 작을수록 Stack 오버플로 위험이 높습니다.
C 버전:
#include "FreeRTOS.h"
#include "task.h"
void vMonitoredTask(void *pvParameters) {
char largeBuffer[512]; // 큰 Stack 사용
while(1) {
// 작업 수행
for(int i = 0; i < 512; i++) {
largeBuffer[i] = i % 256;
}
// Stack 사용량 확인
UBaseType_t highWaterMark = uxTaskGetStackHighWaterMark(NULL);
printf("Stack High Water Mark: %d words = %d bytes\n",
highWaterMark, highWaterMark * sizeof(StackType_t));
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
// Stack 크기: 256 words = 1024 bytes
xTaskCreate(vMonitoredTask, "Monitor", 256, NULL, 2, NULL);
vTaskStartScheduler();
while(1);
}
출력 예시:
Stack High Water Mark: 120 words = 480 bytes
(사용된 Stack: 1024 - 480 = 544 bytes)
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
class MonitoredTask : public Task {
private:
char largeBuffer[512];
public:
MonitoredTask() : Task("Monitor", 256, 2) {}
void run() override {
while(1) {
// 작업 수행
for(int i = 0; i < 512; i++) {
largeBuffer[i] = i % 256;
}
// Stack 사용량 확인
UBaseType_t highWaterMark = uxTaskGetStackHighWaterMark(taskHandle);
std::cout << "Stack High Water Mark: " << highWaterMark
<< " words = " << highWaterMark * sizeof(StackType_t)
<< " bytes" << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
int main(void) {
MonitoredTask task;
task.create();
vTaskStartScheduler();
while(1);
}
C 버전:
// FreeRTOSConfig.h에 추가 필요
// #define configUSE_TRACE_FACILITY 1
// #define configUSE_STATS_FORMATTING_FUNCTIONS 1
#include "FreeRTOS.h"
#include "task.h"
#include <string.h>
void vMonitorTask(void *pvParameters) {
char taskListBuffer[512];
while(1) {
printf("\n=== Task 상태 ===\n");
vTaskList(taskListBuffer);
printf("%s\n", taskListBuffer);
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
int main(void) {
xTaskCreate(vTask1, "Task1", 128, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", 256, NULL, 2, NULL);
xTaskCreate(vTask3, "Task3", 512, NULL, 3, NULL);
xTaskCreate(vMonitorTask, "Monitor", 256, NULL, 4, NULL);
vTaskStartScheduler();
while(1);
}
출력 예시:
=== Task 상태 ===
Name State Priority Stack Num
Task1 R 1 100 1
Task2 B 2 200 2
Task3 B 3 450 3
Monitor R 4 180 4
IDLE R 0 50 5
State: R=Running, B=Blocked, S=Suspended, D=Deleted
C 버전:
// FreeRTOSConfig.h에 추가
// #define configCHECK_FOR_STACK_OVERFLOW 2
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
// Stack Overflow 발생 시 호출됨
printf("!!! Stack Overflow 감지 !!!\n");
printf("Task: %s\n", pcTaskName);
// 긴급 처리
// - 시스템 리셋
// - 에러 로그 저장
// - LED 경고 표시
while(1) {
// 무한 루프로 시스템 정지
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_13);
HAL_Delay(100);
}
}
C++ 버전:
class StackMonitor {
public:
static void reportOverflow(TaskHandle_t xTask, const char* taskName) {
std::cout << "!!! Stack Overflow 감지 !!!" << std::endl;
std::cout << "Task: " << taskName << std::endl;
// 긴급 처리
emergencyHandler();
}
private:
static void emergencyHandler() {
while(1) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_13);
HAL_Delay(100);
}
}
};
extern "C" void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
StackMonitor::reportOverflow(xTask, pcTaskName);
}
C 버전:
#include "FreeRTOS.h"
#include "task.h"
void print_task_info(TaskHandle_t xTask) {
if(xTask == NULL) return;
// 우선순위
UBaseType_t priority = uxTaskPriorityGet(xTask);
// Stack 여유 공간
UBaseType_t stackMark = uxTaskGetStackHighWaterMark(xTask);
// Task 이름
const char* name = pcTaskGetName(xTask);
// Task 상태
eTaskState state = eTaskGetState(xTask);
const char* stateStr[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted"};
printf("Task: %s\n", name);
printf(" 우선순위: %d\n", priority);
printf(" 상태: %s\n", stateStr[state]);
printf(" Stack 여유: %d words\n", stackMark);
}
int main(void) {
TaskHandle_t xHandle;
xTaskCreate(vMyTask, "MyTask", 256, NULL, 2, &xHandle);
vTaskDelay(pdMS_TO_TICKS(100));
print_task_info(xHandle);
vTaskStartScheduler();
while(1);
}
C++ 버전:
class TaskInfo {
public:
static void print(const Task& task) {
TaskHandle_t handle = task.getHandle();
if(handle == nullptr) return;
UBaseType_t priority = uxTaskPriorityGet(handle);
UBaseType_t stackMark = uxTaskGetStackHighWaterMark(handle);
const char* name = pcTaskGetName(handle);
eTaskState state = eTaskGetState(handle);
const char* stateStr[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted"};
std::cout << "Task: " << name << std::endl;
std::cout << " 우선순위: " << priority << std::endl;
std::cout << " 상태: " << stateStr[state] << std::endl;
std::cout << " Stack 여유: " << stackMark << " words" << std::endl;
}
};
| 측면 | C 방식 | C++ 방식 |
|---|---|---|
| Task 생성 | 함수 포인터 직접 전달 | 클래스 메서드로 캡슐화 |
| 핸들 관리 | 전역 변수 또는 매개변수 | 멤버 변수로 관리 |
| 우선순위 변경 | vTaskPrioritySet() 직접 호출 | setPriority() 메서드 |
| 상태 조회 | uxTaskPriorityGet() 직접 호출 | getPriority() 메서드 |
| 삭제 | vTaskDelete() 직접 호출 | 소멸자에서 처리 가능 |
C 방식을 선택할 때:
C++ 방식을 선택할 때:
동적으로 Task를 생성하고 일정 시간 후 자동 삭제하는 시스템을 작성하시오.
요구사항:
C 함수 프로토타입:
void vTimedTask(void *pvParameters);
C++ 클래스:
class TimedTask : public Task {
private:
int lifetime; // 초 단위
public:
TimedTask(int seconds);
void run() override;
};
3개의 Task를 생성하고, 시스템 부하에 따라 우선순위를 동적으로 조정하시오.
요구사항:
모든 Task의 Stack 사용량을 주기적으로 확인하고, 임계값 이하면 경고를 출력하시오.
요구사항:
1. Task 생성 방식
2. Task 삭제 주의사항
3. Stack 관리