RTOS(Real-Time Operating System)를 공부하는 분들이라면 이벤트 플래그를 통해 태스크 간 동기화를 어떻게 처리하는지 잘 이해하셔야 합니다. 본 포스팅에서는 이벤트 플래그 그룹 생성, 대기(Pend) 방식, 비트 제어(포스트) 방식에 대해 순차적으로 살펴보겠습니다.
목차
- 이벤트 플래그(Event Flag)란?
- 이벤트 플래그 그룹과 자료구조
- 이벤트 플래그 그룹 생성: OSFlagCreate()
- 이벤트 플래그 대기: OSFlagPend()
- 이벤트 플래그 설정/해제: OSFlagPost()
- 마무리 및 참고
1. 이벤트 플래그(Event Flag)란?
이벤트 플래그는 여러 태스크(Task)가 특정 조건(비트 패턴)이 만족될 때까지 대기하거나, 만족되었을 때 이를 알려주는 역할을 하는 동기화 기법입니다.
- 비트의 ON/OFF 여부에 따라 태스크들이 원하는 ‘이벤트 발생(비트 ON)’ 혹은 ‘이벤트 소멸(비트 OFF)’을 기다릴 수 있습니다.
- uC/OS-II에서는 이벤트 플래그를 8/16/32비트로 관리할 수 있습니다. (컴파일 옵션 및 RTOS 설정에 따라 달라짐)
이벤트 플래그는 태스크 간 자원 공유, 센서 데이터 준비 완료 신호, 타이머나 인터럽트 처리가 끝났음을 알리는 등 다양한 상황에서 사용됩니다.
2. 이벤트 플래그 그룹과 자료구조
uC/OS-II에서는 이벤트 플래그를 ‘그룹(Group)’ 단위로 관리합니다. 각 그룹은 다음과 같은 정보를 포함합니다.
c
복사편집
typedef struct {
INT8U OSFlagType; // 이 구조가 이벤트 플래그임을 표시
void *OSFlagWaitList; // 이 플래그를 기다리는 태스크들에 대한 대기 리스트
OS_FLAGS OSFlagFlags; // 이벤트 플래그(비트) 상태
} OS_FLAG_GRP;
- OSFlagWaitList는 이 이벤트 플래그 그룹을 기다리고 있는 태스크들의 연결 리스트를 가리킵니다.
- OSFlagFlags는 각 이벤트의 ON/OFF(비트 1/0) 상태를 나타냅니다.
또한, 태스크가 이벤트 플래그를 기다릴 때 생기는 구조체인 OS_FLAG_NODE도 존재합니다.
c
복사편집
typedef struct {
void *OSFlagNodeNext;
void *OSFlagNodePrev;
void *OSFlagNodeTCB; // 플래그를 기다리는 태스크의 TCB
void *OSFlagNodeFlagGrp; // 어느 이벤트 플래그 그룹을 기다리는지
OS_FLAGS OSFlagNodeFlags; // 기다리는 비트 패턴(예: 0xD1)
INT8U OSFlagNodeWaitType; // AND 또는 OR 조건 등
} OS_FLAG_NODE;
- OSFlagNodeFlags: 태스크가 대기하는 비트 패턴 저장
- OSFlagNodeWaitType: AND 대기(모든 비트가 1이어야), OR 대기(한 비트만 1이어도) 등 대기 유형 표시
요약
- OS_FLAG_GRP: 이벤트 플래그의 그룹 상태 및 대기 리스트 정보
- OS_FLAG_NODE: 각 태스크가 기다리는 비트와 대기 조건을 관리
3. 이벤트 플래그 그룹 생성: OSFlagCreate()
이벤트 플래그 그룹을 생성하려면 OSFlagCreate() 함수를 사용합니다.
c
복사편집
OS_EVENT *OSFlagCreate (OS_FLAGS flags, INT8U *err)
{
OS_FLAG_GRP *pgrp;
OS_ENTER_CRITICAL();
pgrp = OSFlagFreeList; // 사용 가능한 OS_FLAG_GRP 구조체 가져오기
if (pgrp != (OS_FLAG_GRP *)0) {
OSFlagFreeList = (OS_FLAG_GRP *)OSFlagFreeList->OSFlagWaitList;
pgrp->OSFlagType = OS_EVENT_TYPE_FLAG; // 이벤트 타입 설정
pgrp->OSFlagFlags = flags; // 초기 플래그(비트) 설정
pgrp->OSFlagWaitList = (void *)0; // 대기 리스트 초기화(아직 대기 태스크 없음)
OS_EXIT_CRITICAL();
*err = OS_NO_ERR; // 에러 없음
} else {
// 생성 불가 시 처리
OS_EXIT_CRITICAL();
*err = OS_ERR_FLAG_CREATE;
return (OS_EVENT *)0;
}
return (pgrp);
}
- flags: 이벤트 플래그 그룹을 생성할 때 초기값으로 설정할 비트 패턴
- OS_MAX_FLAGS: uC/OS-II 설정 파일(OS_CFG.H)에서 최대 생성 가능한 이벤트 플래그 그룹 수를 정의
해당 함수를 호출하면 새로운 이벤트 플래그 그룹이 만들어져, 이후 비트 조작이나 대기를 할 수 있게 됩니다.
4. 이벤트 플래그 대기: OSFlagPend()
4.1 사용 목적
OSFlagPend() 함수는 특정 플래그(비트)가 만족될 때까지 태스크를 대기 상태로 전환시키는 역할을 합니다. 예를 들어,
- 모든 비트가 ON(1)이 되어야 태스크를 깨운다 (AND 조건)
- 비트 중 하나라도 ON(1)이면 태스크를 깨운다 (OR 조건)
- 반대로 OFF(0)를 기다릴 수도 있음
4.2 함수 원형
c
복사편집
OS_FLAG_GRP *OSFlagPend (
OS_FLAG_GRP *pgrp,
OS_FLAGS flags,
INT8U wait_type,
INT16U timeout,
INT8U *err
)
- pgrp: 대기할 이벤트 플래그 그룹
- flags: 대기할 비트 패턴(예: 0x0F)
- wait_type: AND 대기(모든 비트), OR 대기(아무 비트 하나) 등
- timeout: 시간 초과(타임아웃) 설정. 만약 그 시간이 지나도 조건이 만족 안 되면 에러 반환
- *err: 에러 상태를 반환받기 위한 변수
4.3 동작 방식 개요
- 이벤트 플래그 그룹의 현재 상태(pgrp->OSFlagFlags)와 flags를 비교
- 조건이 이미 만족한다면(비트가 이미 ON 또는 OFF) 즉시 반환
- 조건 불만족 시, 태스크를 대기 상태로 만들고 OSFlagWaitList에 연결(이 과정에서 OS_FLAG_NODE 생성)
- 다른 태스크나 인터럽트에서 해당 비트가 만족되는 순간, OSFlagPost()를 통해 깨어남
- 지정한 타임아웃 내에 조건이 만족되지 않으면 에러 코드(OS_TIMEOUT) 반환
예시: AND 대기(모든 비트가 켜질 때까지 대기)
c
복사편집
case OS_FLAG_WAIT_SET_ALL:
flags_rdy = pgrp->OSFlagFlags & flags;
if (flags_rdy == flags) {
// 이미 조건 만족 -> 플래그 수정, 태스크 즉시 진행
pgrp->OSFlagFlags &= ~flags_rdy;
} else {
// 불만족 -> 대기 상태로 전환
// OS_FlagBlock() 내부에서 대기 리스트에 추가
}
5. 이벤트 플래그 설정/해제: OSFlagPost()
5.1 함수 설명
다른 태스크나 인터럽트 서비스 루틴(ISR)에서 특정 이벤트가 발생했음을 알리려면, 이벤트 플래그를 ON(1)으로 설정하거나 때로는 OFF(0)으로 바꿔주어야 합니다.
OSFlagPost() 함수를 이용하면 이벤트 플래그 그룹 내 비트를 ‘설정(SET)’ 혹은 ‘해제(CLEAR)’ 할 수 있습니다.
5.2 함수 원형
c
복사편집
OS_EVENT *OSFlagPost (
OS_FLAG_GRP *pgrp,
OS_FLAGS flags,
INT8U opt,
INT8U *err
)
- pgrp: 수정할 이벤트 플래그 그룹
- flags: 켜거나 끌(ON/OFF) 비트 패턴
- opt: 설정(SET)인지 해제(CLEAR)인지, AND/OR 대기 해제 조건 등
- *err: 에러 상태 반환
5.3 코드 예시
c
복사편집
switch (opt) {
case OS_FLAG_CLR:
// 특정 비트 OFF
pgrp->OSFlagFlags &= ~flags;
break;
case OS_FLAG_SET:
// 특정 비트 ON
pgrp->OSFlagFlags |= flags;
break;
// 필요에 따라 WAIT_SET_ALL, WAIT_SET_ANY 등 분기
}
비트가 업데이트된 이후, 이 플래그를 기다리던 태스크들의 대기 조건이 충족되면 Ready(준비 상태)로 전환됩니다. 이후 스케줄러에 의해 해당 태스크가 CPU를 점유할 수 있게 됩니다.
6. 마무리 및 참고
6.1 핵심 요약
- OS_FLAG_GRP: 이벤트 플래그 그룹의 핵심 구조체
- OSFlagCreate(): 이벤트 플래그 그룹 생성
- OSFlagPend(): 원하는 비트 패턴 만족 시까지 태스크를 대기
- OSFlagPost(): 이벤트 플래그 비트 ON/OFF로 다른 태스크 깨우기
이벤트 플래그는 태스크 간 동기화에 매우 유용합니다. 특히, 여러 개의 자원을 기다리거나 여러 신호 중 하나만 오면 바로 처리해야 하는 경우(OR 대기), 모든 신호가 완료될 때까지 기다리는 경우(AND 대기) 등 다양한 시나리오에 적용할 수 있습니다.
6.2 참고 사항
- OS_MAX_FLAGS 설정: 프로젝트에서 사용할 이벤트 플래그 그룹 개수가 충분히 커야 합니다.
- 이벤트 플래그는 세마포어나 큐, 메일박스와 함께 uC/OS-II의 대표적인 IPC(Inter-Process Communication) 기법 중 하나입니다.
- 실제 코드 구현 시 타임아웃, 인터럽트 우선순위 등을 고려해야 합니다.
- uC/OS-II 이벤트 플래그, Real-Time OS, RTOS 이벤트 플래그, Event Flag Group, OSFlagCreate, OSFlagPend, OSFlagPost, 플래그 동기화, 태스크 동기화, 임베디드 RTOS
이상으로 uC/OS-II 이벤트 플래그(Event Flag) 관리에 대한 전반적인 내용을 살펴보았습니다. RTOS 설계나 임베디드 시스템에서 태스크 간 동기화가 필요한 상황이라면, 이벤트 플래그를 어떻게 설정하고 대기(펜딩)하며, 언제 포스트하는지 숙지해두면 많은 도움이 될 것입니다.
글이 도움되셨다면, 공감(좋아요)과 댓글 부탁드립니다!
궁금한 점이 있으면 언제든 댓글로 남겨주세요. 감사합니다.
참고 링크
- uC/OS-II 공식 문서
- 임베디드 RTOS 실습 자료