지노랩 /JinoLab
한 눈에 정리하는 FreeRTOS Task State - BLOCKED vs. SUSPENDED 본문
RTOS를 쓰다 보면
“태스크가 안 돌아요…” “언제 깨어나는 거죠?” 같은 질문을 매번 하게 됩니다.
이번 글에서는 가장 헷갈리는 BLOCKED 상태와 SUSPENDED 상태를 중심으로,
Delay API·동기화 오브젝트까지 실전 위주로 정리했습니다.
1. 4대 최상위(Task) 상태 복습
상태 의미 전이(Transition)
Running | CPU 독점 실행 중 | ❌ (오직 1 개) |
Ready | 실행 조건 만족 ➜ CPU 할당만 대기 | ▸ 스케줄러가 우선순위 기준 선택 |
Blocked | 이벤트·시간·자원 을 기다리며 “잠시 쉼” | ▸ 이벤트/타임아웃 발생 → Ready |
Suspended | 사용자 호출로 ‘중단’ – 커널도 안 깨움 | ▸ vTaskResume() 으로만 Ready |
포인트
- Blocked ↔ Ready 는 자동 전환
- Suspended ↔ Ready 는 수동 전환
2. BLOCKED : 조건 충족 때까지 “자동 대기”
2-1. 진입 방법
API / 오브젝트 대기 조건
vTaskDelay( ticks ) | 설정한 Tick 수 경과 |
vTaskDelayUntil( &xLastWake, period ) | 정확한 주기 유지 |
xQueueReceive( xQ, …, ticks ) | 큐에 데이터 OR 타임아웃 |
xSemaphoreTake( xSem, ticks ) | 세마포어 가용 OR 타임아웃 |
→ 호출 즉시 Running → Blocked
→ CPU 사이클 0 % 사용 (즉, 저전력)
/* 100 ms 동안 CPU 반납 */
vTaskDelay( pdMS_TO_TICKS(100) );
2-2. 깨어나는 시점
- 이벤트 충족 (큐에 데이터, 세마포어 획득 등)
- 타임아웃 – 지정 시간이 지나도 이벤트 없으면 Ready로 자동 복귀
Tip
타임아웃=0 을 주면 “영원히” 기다릴 수 있음 (portMAX_DELAY)
3. SUSPENDED : “커널도 모른 척, 네가 깨워”
3-1. 진입 / 복귀 API
vTaskSuspend( xHandle ); // 어떤 상태든 → Suspended
vTaskResume( xHandle ); // 실행권 회복 (Ready)
vTaskResumeFromISR( xHandle ); // ISR 내 복귀
- 자동 타임아웃 없음
- 다른 태스크/ISR이 명시적으로 Resume 해 줘야만 Ready 전환
3-2. 언제 쓰나?
사용 시나리오 이유
펌웨어 OTA 중 특정 태스크 ‘잠깐 OFF’ | 업데이트 충돌 방지 |
모드 전환(예: 저속↔고속) | 불필요한 태스크 완전 정지 |
테스트/디버그용 태스크 임시 중단 | 로직 단순화 |
4. BLOCKED vs. SUSPENDED 비교표
항목 Blocked Suspended
진입 방식 | Delay·큐·세마포어 등 커널 API | vTaskSuspend() (수동) |
깨어남 | 이벤트 or 타임아웃 자동 | vTaskResume() 수동 |
타임아웃 | O | X |
용도 | 지연·동기화 | 모드 전환·임시 중단 |
Ready로 가는 길 | 커널이 판단 | 사용자/ISR 호출 |
5. Delay API 빠르게 쓰는 법
5-1. vTaskDelay()
/* 500 ms 슬립 */
vTaskDelay( pdMS_TO_TICKS(500) );
- 지연 후 실행 시점이 Tick 해상도에 ±1 틱 오차
- 간단-최소 코드에 적합
5-2. vTaskDelayUntil()
void vTask(void *arg)
{
TickType_t xLast = xTaskGetTickCount();
const TickType_t period = pdMS_TO_TICKS(10);
for(;;)
{
/* 정확히 10 ms 간격으로 실행 */
vTaskDelayUntil( &xLast, period );
doJob();
}
}
- 이전 실행 시점 기준, 정확한 주기 유지
- 주기성 요구(센서 폴링, PID 루프 등)에 필수
6. 실전 팁 & 주의사항
- 큐/세마포어는 “0 Tick 타임아웃”으로 폴링하지 말 것 –
Blocked 상태를 활용해 CPU ‘놀지’ 않게 한다. - 지연 대신 Suspend?
- 지연(Delay)은 반드시 다시 깨어남 → 주기성에 좋음
- Suspend는 이벤트 없이 영구 중단될 수 있으니 로직 설계 주의
- Idle Hook + 낮은 Tick Rate로 저전력 최적화
- Race Condition 디버깅: eTaskGetState()로 태스크 상태 실시간 로깅
마무리
- Blocked = “조건 충족 시 자동 복귀”
- Suspended = “_사용자_가 깨울 때까지 휴면”
두 상태를 적절히 활용하면
- CPU 부하 ↓
- 전력 소모 ↓
- 코드 가독성 ↑
다음 글에서는 큐·세마포어·이벤트그룹을 이용한 _실전 동기화 패턴_을 다루겠습니다.
궁금한 점은 댓글로 남겨 주세요!
'임베디드 시스템 > RTOS' 카테고리의 다른 글
FreeRTOS Task Notification (0) | 2025.06.22 |
---|---|
Delay 제대로 쓰기! vTaskDelay() vs. vTaskDelayUntil() 한방 정리 (1) | 2025.06.22 |
FreeRTOS(Task) 상태 정리 – 한 눈에 이해하는 Running·Ready·Blocked·Suspended (1) | 2025.06.21 |
50.FreeRTOS 컨텍스트 스위치 ― PendSV 핸들러 단계별 해부 (0) | 2025.06.20 |
PendSV _Handler 안에서 “스위치-아웃 ⟶ 스케줄러 호출 ⟶ 스위치-인”이 구현되는 실제 흐름 (1) | 2025.06.20 |