RTOS 기반 설계에 적용되는 비재진입 함수에 관한 취급 설명서
본 기사는 RTOS 전문가인 Jean J. Labrosse가 작성하였습니다.
재진입vs 비재진입 함수:
공통 함수가 로컬 변수만 사용하는 경우, (컴파일러 자체가 재진입 코드를 생성한다고 가정할 때,) 재진입하는 것이 일반적입니다.
반대로, 비재진입 함수는 하나 이상의 광역 변수를 사용하여 함수의 상태를 추적하는 함수입니다. IAR 도구 체인에 관한 온라인 문서에서 그림 1과 같이 비재진입 함수의 목록을 확인할 수 있습니다.
그림 1. IAR STD 라이브러리에서 확인가능한 비재진입 함수의 목록
DLIB 런타임 C 라이브러리인 string.h: strtok()은 비재진입 함수의 좋은 사례입니다. 이 함수는 "토큰"에 대한 ASCII 문자열의 구문을 분석하기 위해 사용합니다. IAR 문서의 strtok()에 대한 설명은 그림 2에 도시되어 있습니다.
그림 2. 비재진입 함수인 strtok()에 대한 설명
- 그림 3에 표시된 간단한(부분적인) 코드 예제는 strtok()의 사용 사례입니다. ptoken은 string[]에서 추출한 다음 토큰(즉, 동물 이름 중 하나)의 시작 부분에 대한 포인터입니다.
- strtok()을 처음 호출할 때, 구문 분석 대상의 ASCII 문자열(즉, string[])과 토큰 구분 기호 목록(하나 이상의 구분 기호일 수 있음)을 지정합니다(이 예에서 ","(단일 쉼표)). 이 함수는 첫 번째 구분 기호를 찾고 string[]의 해당 구분 기호를 NULstrtok()으로 교체한 다음, string[]의 다음 문자(즉, 다음 토큰)에 내부 포인터(internal pointer)를 배치하는 즉시 반환합니다.
- strtok()에 대한 두 번째(그리고 후속) 호출에 대한 첫 번째 인수로서, NULL 포인터(이와 같은 경우에 저는 0을 사용합니다.)를 지정해야 합니다. 두 번째 인수에는 다른 구분 문자를 찾아야 하는 경우 다를 수 있는 토큰 구분 기호가 포함되어 있기는 하지만, 이 경우에는 쉼표를 유지했습니다.
- 또 다시 strtok()에 대한 두 번째(및 후속) 호출에 대한 첫 번째 인수로서 다음 토큰을 추출하려면 NULL 포인터를 지정해야 합니다(이 경우 0을 사용했습니다). 두 번째 인수에는 토큰 구분 기호가 포함됩니다.
- strtok()이 NULL을 반환할 때까지, NULL 포인터와 원하는 구분 기호를 계속 전달합니다. 그 시점에서 string[]에는 더 이상 토큰이 없습니다.
1) char *ptoken;
char string[80] = “Lion,Tiger,Panther”;
2) ptoken = strtok(string, “,”);
ptoken contains “Lion”
The internal pointer points to the T in Tiger.
3) ptoken = strtok(0, “,”);
ptoken contains “Tiger”
The internal pointer points to the P in Panther.
4) ptoken = strtok(0, “,”);
ptoken contains “Panther”
The internal pointer points to the NUL at the end of string[].
5) ptoken = strtok(0, “,”);
ptoken contains a NULL pointer because there are no more tokens
그림 3. strtok() 호출 순서
물론 많은 토큰이 예상되는 경우 루프에서 strtok()을 구현할 수 있습니다.
RTOS 애플리케이션에서의 비재진입 함수 사용:
strtok()(및 기타 비 재진입 함수)가 다음 토큰을 추적하는 내부 포인터를 유지한다는 사실을 강조하는 것이 이전 논의의 요점입니다.
일반적으로 RTOS 애플리케이션에서는 비재진입 함수를 적용하지 않는 것이 좋습니다. 그러나 일부 비재진입 함수에서 제공되는 기능이 필요한 경우, RTOS 애플리케이션 코드는 다음 중 하나를 수행해야 합니다.
- 구현하고자 하는 비재진입 함수의 재진입 가능 버전을 구현합니다.
- 하나의 작업에서 strtok()(그리고 기타 비재진입 함수)만 사용하십시오. 그럼에도 불구하고, 각 작업에는 고유하게 작용하는 비재진입 함수가 존재할 수 있습니다.
- 비재진입 함수는 뮤텍스를 사용하여 보호해야 하는 공유 리소스입니다.
그림 4의 의사 코드 스니펫은 뮤텍스를 사용하여 비재진입 함수에 대한 접근을 보호하는 방법을 도시하고 있습니다.
// Allocate storage for the mutex
// Initialize the mutex before any functions that uses strtok()
void MyTask (void)
{
// Initialize task variables and I/Os as needed
while (1) {
// Wait for the event to wake up ‘MyTask’
:
:
// Get string with tokens
AcquireMutex(..);
// Extract token(s) from desired string;
ReleaseMutex(..);
:
:
}
}
그림 4. 비재진입 함수에 대한 배타적 액세스 보장
strtok()을 사용하는 각 작업은 상기 구문에서와 같이 뮤텍스를 획득/해제해야 합니다. 또는 토큰 배열의 내부로 토큰을 구문 분석하는 함수(즉, 애플리케이션 코드에 대한 서비스)를 구현할 수 있습니다. 이 함수는 뮤텍스 구현 세부 정보를 숨기기 때문에, 모든 작업에서 재진입 불가에 대한 우려 없이 토큰을 추출할 수 있습니다.
또한 세마포어를 사용할 경우 무한정 발생 가능한 우선 순위의 반전 현상을 회피할 수 있기 때문에, 뮤텍스의 사용을 지정했습니다.
저자 소개
본 기사는 RTOS 개발 애플리케이션에 관한 시리즈의 일부입니다.
Jean Labrose는 높은 인지도를 가진 uC/OS-II와 uC/OS-III 커널의 저자이자 Micrium의 설립자로, 임베디드 소프트웨어의 uC/라인의 발전에 적극적으로 관여하고 있습니다.
Jean은 풍부한 경험과 임베디드 시스템 시장에 대한 깊은 이해를 바탕으로 Weston Embedded Solutions의 수석 조언자 및 컨설턴트로 재직하고 있으며, 현재 RTOS 제품의 향후 보다 발전된 제안을 마련하는데 기여하고 있습니다. Weston Embedded Solutions는 Micrium 코드베이스에서 파생된 매우 안정적인 Cesium RTOS 제품군의 지원 및 개발을 전문으로 합니다.
Jean.Labrosse@Weston-Embedded.com.