
우선순위(Priority)는 FreeRTOS 스케줄러가 어느 Task를 먼저 실행할지 결정하는 기준입니다.
숫자가 클수록 우선순위가 높습니다. 우선순위가 높은 Task는 낮은 Task를 선점(Preempt)할 수 있습니다.
| 항목 | 설명 |
|---|---|
| 최소값 | 0 (가장 낮은 우선순위) |
| 최대값 | configMAX_PRIORITIES - 1 |
| Idle Task | 항상 우선순위 0 |
| 설정 위치 | FreeRTOSConfig.h |
FreeRTOSConfig.h 설정:
// FreeRTOSConfig.h
#define configMAX_PRIORITIES 5
// 사용 가능한 우선순위: 0, 1, 2, 3, 4
// 0: Idle Task (시스템 예약)
// 1~4: 사용자 Task
우선순위 예시:
우선순위 4 (최고) ← 긴급한 실시간 작업
우선순위 3 ← 중요한 주기적 작업
우선순위 2 ← 일반 애플리케이션
우선순위 1 ← 백그라운드 작업
우선순위 0 ← Idle Task (시스템 예약)
C 버전:
#include "FreeRTOS.h"
#include "task.h"
void vTask1(void *pvParameters) {
while(1) {
printf("Task 1 실행 (우선순위: 1)\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask2(void *pvParameters) {
while(1) {
printf("Task 2 실행 (우선순위: 2)\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vTask3(void *pvParameters) {
while(1) {
printf("Task 3 실행 (우선순위: 3)\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
//xTaskCreate()내부의 콜백 함수 형태로 태스크 우선순위 부여
int main(void) {
// 우선순위를 다르게 설정
xTaskCreate(vTask1, "Task1", 128, NULL, 1, NULL); // 우선순위 1
xTaskCreate(vTask2, "Task2", 128, NULL, 2, NULL); // 우선순위 2
xTaskCreate(vTask3, "Task3", 128, NULL, 3, NULL); // 우선순위 3
vTaskStartScheduler();
while(1);
}
C++ 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <iostream>
//C언어와는 달리 C++은 캡슐화를 위해 클래스 형태로 태스크 생성
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);
}
UBaseType_t getPriority() const { return priority; }
TaskHandle_t getHandle() const { return taskHandle; }
virtual ~Task() {}
};
class WorkTask : public Task {
private:
int taskId;
public:
WorkTask(int id, UBaseType_t prio)
: Task("WorkTask", 128, prio), taskId(id) {}
void run() override {
while(1) {
std::cout << "Task " << taskId
<< " 실행 (우선순위: " << getPriority() << ")" << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
int main(void) {
WorkTask task1(1, 1); // 우선순위 1
WorkTask task2(2, 2); // 우선순위 2
WorkTask task3(3, 3); // 우선순위 3
task1.create();
task2.create();
task3.create();
vTaskStartScheduler();
while(1);
}
규칙 1: 가장 높은 우선순위의 Ready Task가 실행됨
규칙 2: 같은 우선순위가 여러 개면 Round-robin으로 교대 실행
규칙 3: 높은 우선순위가 Ready되면 즉시 낮은 우선순위를 선점
규칙 4: Blocked/Suspended Task는 실행 대상이 아님
시나리오 1: 우선순위가 모두 다를 때
C 버전:
void vLowPriorityTask(void *pvParameters) {
while(1) {
printf("[LOW] 실행 중... (우선순위: 1)\n");
// Delay 없이 계속 실행
for(volatile int i = 0; i < 100000; i++);
}
}
void vMediumPriorityTask(void *pvParameters) {
while(1) {
printf("[MEDIUM] 실행 중... (우선순위: 2)\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vHighPriorityTask(void *pvParameters) {
while(1) {
printf("[HIGH] 실행 중... (우선순위: 3)\n");
vTaskDelay(pdMS_TO_TICKS(500));
}
}
int main(void) {
xTaskCreate(vLowPriorityTask, "Low", 128, NULL, 1, NULL);
xTaskCreate(vMediumPriorityTask, "Medium", 128, NULL, 2, NULL);
xTaskCreate(vHighPriorityTask, "High", 128, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
실행 흐름:
시간 →
0ms : High, Medium, Low 모두 Ready
→ High 실행 (우선순위 3)
500ms : High가 vTaskDelay() 호출 → Blocked
→ Medium 실행 (우선순위 2)
1000ms : High Ready (Delay 끝)
→ High가 Medium 선점
1500ms : Medium Ready (Delay 끝), High Blocked
→ Medium 실행
2000ms : High Ready
→ High가 Medium 선점
Low Task는 High와 Medium이 모두 Blocked일 때만 실행됨
타이밍 다이어그램:
시간 (ms) 0 500 1000 1500 2000 2500
|-----|-----|-----|-----|-----|
High (3): ████──████──████──████──████──
Medium (2): ────██────██────██────██────
Low (1): ──────────────────────────██
위의 예시는 선점형 스케쥴링의 예시로, 우선순위가 medium인 태스크의 실행 중에 우선순위가 high인 태스크가 ready 상태가 되면 그 즉시 우선순위가 medium인 태스크는 실행을 중지하고 우선순위가 high인 태스크가 실행되게 됩니다. 후에 배울 내용이지만 선점형 스케쥴링을 사용하더라도 우선순위 medium인 태스크가 끝까지 실행돼야 하는 경우라면 뮤텍스(Mutex)와 세마포어(Semaphore)를 사용해 갑작스러운 선점으로부터 시스템의 안정성을 지킬 수 있습니다.
시나리오 2: 같은 우선순위일 때 (Round-robin)
C 버전:
void vTaskA(void *pvParameters) {
int count = 0;
while(1) {
printf("[Task A] Count: %d\n", count++);
// Delay 없이 실행
for(volatile int i = 0; i < 500000; i++);
}
}
void vTaskB(void *pvParameters) {
int count = 0;
while(1) {
printf("[Task B] Count: %d\n", count++);
for(volatile int i = 0; i < 500000; i++);
}
}
void vTaskC(void *pvParameters) {
int count = 0;
while(1) {
printf("[Task C] Count: %d\n", count++);
for(volatile int i = 0; i < 500000; i++);
}
}
int main(void) {
// 모두 같은 우선순위 2
xTaskCreate(vTaskA, "TaskA", 128, NULL, 2, NULL);
xTaskCreate(vTaskB, "TaskB", 128, NULL, 2, NULL);
xTaskCreate(vTaskC, "TaskC", 128, NULL, 2, NULL);
vTaskStartScheduler();
while(1);
}
실행 결과:
[Task A] Count: 0
[Task B] Count: 0
[Task C] Count: 0
[Task A] Count: 1
[Task B] Count: 1
[Task C] Count: 1
[Task A] Count: 2
...
→ A, B, C가 매 Tick마다 순서대로 교대 실행
C++ 버전:
class RoundRobinTask : public Task {
private:
char taskId;
int count;
public:
RoundRobinTask(char id)
: Task("RRTask", 128, 2), taskId(id), count(0) {}
void run() override {
while(1) {
std::cout << "[Task " << taskId << "] Count: " << count++ << std::endl;
for(volatile int i = 0; i < 500000; i++);
}
}
};
int main(void) {
RoundRobinTask taskA('A');
RoundRobinTask taskB('B');
RoundRobinTask taskC('C');
taskA.create();
taskB.create();
taskC.create();
vTaskStartScheduler();
while(1);
}
C 버전:
TaskHandle_t xWorkerHandle;
void vWorkerTask(void *pvParameters) {
while(1) {
printf("Worker 작업 중...\n");
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void vControlTask(void *pvParameters) {
vTaskDelay(pdMS_TO_TICKS(2000)); // 2초 대기
while(1) {
printf(">>> Worker 우선순위 높임\n");
vTaskPrioritySet(xWorkerHandle, 4); // 우선순위 상승
vTaskDelay(pdMS_TO_TICKS(3000));
printf(">>> Worker 우선순위 낮춤\n");
vTaskPrioritySet(xWorkerHandle, 1); // 우선순위 복구
vTaskDelay(pdMS_TO_TICKS(3000));
}
}
int main(void) {
xTaskCreate(vWorkerTask, "Worker", 128, NULL, 1, &xWorkerHandle);
xTaskCreate(vControlTask, "Control", 128, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
실행 흐름:
0-2초: Control이 Delay 중
→ Worker 실행 (우선순위 1)
2초: Control이 Worker 우선순위를 4로 변경
→ Worker가 Control을 선점 (4 > 3)
2-5초: Worker 계속 실행 (우선순위 4)
5초: Control이 Worker 우선순위를 1로 변경
→ Control이 Worker를 선점 (3 > 1)
나중에 더 자세히 다룰 예정이라 간략하게 설명하고 가자면 우선 순위 역전(Priority Inversion)을 방지하기 위해 우선순위가 낮은 태스크에게 "임시 특권"을 주는 방법이라고 설명할 수 있습니다. 이 특권은 태스크의 실행이 완료되면 특권을 사용한 태스크가 직접 반납하도록 돼 있습니다. 아래는 2.3 선점 발생 조건과 같은 예제 코드를 뮤택스 기반으로 리팩토링한 예제 코드입니다.
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
// 공유 자원을 보호하기 위한 뮤텍스 핸들
SemaphoreHandle_t xMutex;
void vWorkerTask(void *pvParameters) {
while(1) {
// 1. 뮤텍스를 획득할 때까지 대기 (열쇠를 얻어야 작업 시작)
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
printf("Worker: 뮤텍스 획득! 중요 작업 시작...\n");
// 실제 업무 수행 (이 동안 우선순위 상속이 발생할 수 있음)
vTaskDelay(pdMS_TO_TICKS(1000));
printf("Worker: 작업 완료, 뮤텍스 반환.\n");
// 2. 작업 완료 후 뮤텍스 반환
xSemaphoreGive(xMutex);
}
// 다음 작업을 위한 대기
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vControlTask(void *pvParameters) {
while(1) {
vTaskDelay(pdMS_TO_TICKS(3000)); // 3초마다 Worker의 자원에 접근 시도
printf(">>> Control: Worker의 자원이 필요함 (접근 시도)...\n");
// 3. Control(높은 우선순위)이 뮤텍스를 요청함
// 만약 이때 Worker가 뮤텍스를 가지고 있다면,
// Worker의 우선순위가 Control 수준(3)으로 자동 상승합니다.
if (xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
printf(">>> Control: 자원 획득 성공! 데이터 처리 중...\n");
vTaskDelay(pdMS_TO_TICKS(500));
xSemaphoreGive(xMutex);
printf(">>> Control: 처리 완료 및 뮤텍스 반환.\n");
}
}
}
int main(void) {
// 뮤텍스 생성
xMutex = xSemaphoreCreateMutex();
if (xMutex != NULL) {
// Worker는 낮은 우선순위(1), Control은 높은 우선순위(3)
xTaskCreate(vWorkerTask, "Worker", 128, NULL, 1, NULL);
xTaskCreate(vControlTask, "Control", 128, NULL, 3, NULL);
vTaskStartScheduler();
}
while(1);
}
함수 원형:
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority);
UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask);
파라미터:
xTask: 변경할 Task의 핸들 (NULL = 자기 자신)uxNewPriority: 새로운 우선순위 (0 ~ configMAX_PRIORITIES-1)반환값:
vTaskPrioritySet: 없음uxTaskPriorityGet: 현재 우선순위C 버전:
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t xTaskHandle;
void vMyTask(void *pvParameters) {
while(1) {
UBaseType_t currentPriority = uxTaskPriorityGet(NULL);
printf("현재 우선순위: %d\n", currentPriority);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void vControlTask(void *pvParameters) {
vTaskDelay(pdMS_TO_TICKS(3000));
// MyTask 우선순위 변경
printf("우선순위 2 → 4로 변경\n");
vTaskPrioritySet(xTaskHandle, 4);
vTaskDelay(pdMS_TO_TICKS(3000));
printf("우선순위 4 → 1로 변경\n");
vTaskPrioritySet(xTaskHandle, 1);
vTaskDelete(NULL);
}
int main(void) {
xTaskCreate(vMyTask, "MyTask", 128, NULL, 2, &xTaskHandle);
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) {
vTaskPrioritySet(taskHandle, newPriority);
priority = newPriority;
}
UBaseType_t getPriority() const {
return uxTaskPriorityGet(taskHandle);
}
TaskHandle_t getHandle() const { return taskHandle; }
virtual ~Task() {}
};
class MonitoredTask : public Task {
public:
MonitoredTask() : Task("Monitored", 128, 2) {}
void run() override {
while(1) {
std::cout << "현재 우선순위: " << getPriority() << std::endl;
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
};
class ControlTask : public Task {
private:
MonitoredTask& target;
public:
ControlTask(MonitoredTask& t) : Task("Control", 128, 3), target(t) {}
void run() override {
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "우선순위 2 → 4로 변경" << std::endl;
target.setPriority(4);
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "우선순위 4 → 1로 변경" << std::endl;
target.setPriority(1);
vTaskDelete(taskHandle);
}
};
int main(void) {
MonitoredTask monitorTask;
ControlTask controlTask(monitorTask);
monitorTask.create();
controlTask.create();
vTaskStartScheduler();
while(1);
}
C 버전:
void vAdaptiveTask(void *pvParameters) {
int workload = 0;
while(1) {
// 작업량에 따라 우선순위 조정
if(workload > 100) {
// 긴급: 우선순위 상승
vTaskPrioritySet(NULL, 4); // NULL = 자기 자신
printf("긴급 모드: 우선순위 4\n");
} else {
// 정상: 우선순위 복구
vTaskPrioritySet(NULL, 2);
printf("정상 모드: 우선순위 2\n");
}
// 작업 수행
process_work(workload);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
C 버전:
typedef enum {
MODE_IDLE,
MODE_NORMAL,
MODE_BUSY,
MODE_CRITICAL
} SystemMode;
SystemMode currentMode = MODE_NORMAL;
void vSensorTask(void *pvParameters) {
while(1) {
read_sensor_data();
// 시스템 모드에 따라 우선순위 조정
switch(currentMode) {
case MODE_IDLE:
vTaskPrioritySet(NULL, 1);
break;
case MODE_NORMAL:
vTaskPrioritySet(NULL, 2);
break;
case MODE_BUSY:
vTaskPrioritySet(NULL, 3);
break;
case MODE_CRITICAL:
vTaskPrioritySet(NULL, 4);
break;
}
UBaseType_t priority = uxTaskPriorityGet(NULL);
printf("센서 Task 우선순위: %d (모드: %d)\n", priority, currentMode);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vModeManagerTask(void *pvParameters) {
while(1) {
// 시스템 상태 확인
float cpuLoad = get_cpu_load();
if(cpuLoad > 90.0) {
currentMode = MODE_CRITICAL;
} else if(cpuLoad > 70.0) {
currentMode = MODE_BUSY;
} else if(cpuLoad > 30.0) {
currentMode = MODE_NORMAL;
} else {
currentMode = MODE_IDLE;
}
printf("CPU 부하: %.1f%%, 모드: %d\n", cpuLoad, currentMode);
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
C++ 버전:
enum class SystemMode {
IDLE,
NORMAL,
BUSY,
CRITICAL
};
class AdaptivePriorityTask : public Task {
private:
SystemMode& mode;
UBaseType_t getPriorityForMode(SystemMode m) {
switch(m) {
case SystemMode::IDLE: return 1;
case SystemMode::NORMAL: return 2;
case SystemMode::BUSY: return 3;
case SystemMode::CRITICAL: return 4;
default: return 2;
}
}
public:
AdaptivePriorityTask(SystemMode& m)
: Task("Adaptive", 128, 2), mode(m) {}
void run() override {
while(1) {
// 센서 데이터 읽기
read_sensor_data();
// 모드에 따라 우선순위 조정
UBaseType_t newPriority = getPriorityForMode(mode);
setPriority(newPriority);
std::cout << "센서 Task 우선순위: " << getPriority()
<< " (모드: " << static_cast<int>(mode) << ")" << std::endl;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
};
원칙: 주기가 짧은 Task에 높은 우선순위를 할당
C 버전:
// 10ms 주기 Task → 우선순위 4 (가장 높음)
void vFastTask(void *pvParameters) {
while(1) {
process_fast_data();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
// 50ms 주기 Task → 우선순위 3
void vMediumTask(void *pvParameters) {
while(1) {
process_medium_data();
vTaskDelay(pdMS_TO_TICKS(50));
}
}
// 100ms 주기 Task → 우선순위 2
void vSlowTask(void *pvParameters) {
while(1) {
process_slow_data();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// 비주기적 작업 → 우선순위 1 (가장 낮음)
void vBackgroundTask(void *pvParameters) {
while(1) {
process_background_work();
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
xTaskCreate(vFastTask, "Fast", 128, NULL, 4, NULL);
xTaskCreate(vMediumTask, "Medium", 128, NULL, 3, NULL);
xTaskCreate(vSlowTask, "Slow", 128, NULL, 2, NULL);
xTaskCreate(vBackgroundTask, "Background", 128, NULL, 1, NULL);
vTaskStartScheduler();
while(1);
}
C 버전:
// 안전 중요 Task → 우선순위 4
void vSafetyTask(void *pvParameters) {
while(1) {
check_safety_conditions();
if(emergency_detected()) {
trigger_emergency_stop();
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
// 실시간 제어 Task → 우선순위 3
void vControlTask(void *pvParameters) {
while(1) {
read_sensors();
calculate_control_output();
actuate_motors();
vTaskDelay(pdMS_TO_TICKS(20));
}
}
// 통신 Task → 우선순위 2
void vCommTask(void *pvParameters) {
while(1) {
process_can_messages();
vTaskDelay(pdMS_TO_TICKS(100));
}
}
// UI 업데이트 Task → 우선순위 1
void vUITask(void *pvParameters) {
while(1) {
update_display();
vTaskDelay(pdMS_TO_TICKS(500));
}
}
| 우선순위 | 용도 | 주기 예시 | 예제 |
|---|---|---|---|
| 4 (최고) | 안전 중요, 긴급 대응 | < 10ms | 비상 정지, 안전 감시 |
| 3 | 실시간 제어 | 10-50ms | 모터 제어, 센서 샘플링 |
| 2 | 일반 애플리케이션 | 50-200ms | 통신, 데이터 처리 |
| 1 | 백그라운드 작업 | > 200ms | UI, 로깅, 통계 |
| 0 | Idle Task | - | 시스템 예약 |
목표: 우선순위에 따른 Task 실행 순서 확인
C 버전:
#include "FreeRTOS.h"
#include "task.h"
#include <stdio.h>
void vTask(void *pvParameters) {
int taskId = (int)pvParameters;
UBaseType_t priority = uxTaskPriorityGet(NULL);
while(1) {
printf("[Task %d] 우선순위: %d 실행 중\n", taskId, priority);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
int main(void) {
// 서로 다른 우선순위로 3개 Task 생성
xTaskCreate(vTask, "Task1", 128, (void*)1, 1, NULL);
xTaskCreate(vTask, "Task2", 128, (void*)2, 2, NULL);
xTaskCreate(vTask, "Task3", 128, (void*)3, 3, NULL);
vTaskStartScheduler();
while(1);
}
예상 결과:
[Task 3] 우선순위: 3 실행 중
[Task 2] 우선순위: 2 실행 중
[Task 1] 우선순위: 1 실행 중
[Task 3] 우선순위: 3 실행 중
...
목표: vTaskPrioritySet()으로 실행 중 우선순위 변경
C 버전:
TaskHandle_t xTask1Handle, xTask2Handle, xTask3Handle;
void vTask(void *pvParameters) {
int taskId = (int)pvParameters;
while(1) {
UBaseType_t priority = uxTaskPriorityGet(NULL);
printf("[Task %d] 우선순위: %d\n", taskId, priority);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vControlTask(void *pvParameters) {
while(1) {
vTaskDelay(pdMS_TO_TICKS(3000));
printf("\n>>> Task1 우선순위 1 → 4로 상승\n");
vTaskPrioritySet(xTask1Handle, 4);
vTaskDelay(pdMS_TO_TICKS(3000));
printf("\n>>> Task1 우선순위 4 → 1로 복구\n");
vTaskPrioritySet(xTask1Handle, 1);
vTaskDelay(pdMS_TO_TICKS(3000));
printf("\n>>> Task2 우선순위 2 → 4로 상승\n");
vTaskPrioritySet(xTask2Handle, 4);
vTaskDelay(pdMS_TO_TICKS(3000));
printf("\n>>> Task2 우선순위 4 → 2로 복구\n");
vTaskPrioritySet(xTask2Handle, 2);
}
}
int main(void) {
xTaskCreate(vTask, "Task1", 128, (void*)1, 1, &xTask1Handle);
xTaskCreate(vTask, "Task2", 128, (void*)2, 2, &xTask2Handle);
xTaskCreate(vTask, "Task3", 128, (void*)3, 3, &xTask3Handle);
xTaskCreate(vControlTask, "Control", 256, NULL, 3, NULL);
vTaskStartScheduler();
while(1);
}
C++ 버전:
class ExperimentTask : public Task {
private:
int taskId;
public:
ExperimentTask(int id, UBaseType_t prio)
: Task("Task", 128, prio), taskId(id) {}
void run() override {
while(1) {
std::cout << "[Task " << taskId << "] 우선순위: "
<< getPriority() << std::endl;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
};
class PriorityControlTask : public Task {
private:
ExperimentTask& task1;
ExperimentTask& task2;
public:
PriorityControlTask(ExperimentTask& t1, ExperimentTask& t2)
: Task("Control", 256, 3), task1(t1), task2(t2) {}
void run() override {
while(1) {
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "\n>>> Task1 우선순위 상승\n";
task1.setPriority(4);
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "\n>>> Task1 우선순위 복구\n";
task1.setPriority(1);
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "\n>>> Task2 우선순위 상승\n";
task2.setPriority(4);
vTaskDelay(pdMS_TO_TICKS(3000));
std::cout << "\n>>> Task2 우선순위 복구\n";
task2.setPriority(2);
}
}
};
int main(void) {
ExperimentTask task1(1, 1);
ExperimentTask task2(2, 2);
ExperimentTask task3(3, 3);
PriorityControlTask controlTask(task1, task2);
task1.create();
task2.create();
task3.create();
controlTask.create();
vTaskStartScheduler();
while(1);
}
목표: 시스템 상태에 따라 자동으로 우선순위 조정
C 버전:
typedef struct {
TaskHandle_t handle;
UBaseType_t normalPriority;
UBaseType_t boostPriority;
} AdaptiveTask;
AdaptiveTask tasks[3];
volatile float cpuLoad = 0;
void vWorkerTask(void *pvParameters) {
int taskId = (int)pvParameters;
while(1) {
UBaseType_t priority = uxTaskPriorityGet(NULL);
printf("[Task %d] 우선순위: %d, CPU 부하: %.1f%%\n",
taskId, priority, cpuLoad);
// 실제 작업 시뮬레이션
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vLoadMonitorTask(void *pvParameters) {
while(1) {
// CPU 부하 시뮬레이션 (0-100%)
cpuLoad = (cpuLoad + 10.0);
if(cpuLoad > 100.0) cpuLoad = 0;
// 부하에 따라 우선순위 조정
if(cpuLoad > 80.0) {
// 고부하: 모든 Task 우선순위 상승
for(int i = 0; i < 3; i++) {
vTaskPrioritySet(tasks[i].handle, tasks[i].boostPriority);
}
printf("\n>>> 고부하 모드: 우선순위 상승\n");
} else if(cpuLoad < 30.0) {
// 저부하: 정상 우선순위 복구
for(int i = 0; i < 3; i++) {
vTaskPrioritySet(tasks[i].handle, tasks[i].normalPriority);
}
printf("\n>>> 정상 모드: 우선순위 복구\n");
}
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
int main(void) {
// Task 초기화
tasks[0].normalPriority = 1;
tasks[0].boostPriority = 3;
xTaskCreate(vWorkerTask, "Task1", 128, (void*)1,
tasks[0].normalPriority, &tasks[0].handle);
tasks[1].normalPriority = 2;
tasks[1].boostPriority = 4;
xTaskCreate(vWorkerTask, "Task2", 128, (void*)2,
tasks[1].normalPriority, &tasks[1].handle);
tasks[2].normalPriority = 1;
tasks[2].boostPriority = 3;
xTaskCreate(vWorkerTask, "Task3", 128, (void*)3,
tasks[2].normalPriority, &tasks[2].handle);
xTaskCreate(vLoadMonitorTask, "Monitor", 256, NULL, 2, NULL);
vTaskStartScheduler();
while(1);
}
| 측면 | C 방식 | C++ 방식 |
|---|---|---|
| 우선순위 설정 | xTaskCreate() 직접 지정 | 생성자에서 멤버 변수로 관리 |
| 우선순위 변경 | vTaskPrioritySet() 직접 호출 | setPriority() 메서드 |
| 우선순위 조회 | uxTaskPriorityGet() 직접 호출 | getPriority() 메서드 |
| 핸들 관리 | 전역 변수 또는 매개변수 | 멤버 변수로 캡슐화 |
| 그룹 관리 | 배열 또는 구조체 | 클래스 계층 또는 컨테이너 |
C 방식을 선택할 때:
C++ 방식을 선택할 때:
| 개념 | 설명 |
|---|---|
| 선점 (Preemption) | 높은 우선순위가 낮은 우선순위를 중단시키고 실행 |
| Round-robin | 같은 우선순위 Task의 시분할 실행 |
| Priority Inversion | 낮은 우선순위가 높은 우선순위를 막는 현상 |
| Priority Inheritance | Mutex 대기 시 우선순위를 일시적으로 상승 |