산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial Internet of Things >> 임베디드

Nucleus SE의 세마포어: 개요, 구성, API 핵심

Nucleus SE의 세마포어: 개요, 구성, API 핵심
RTOS Revealed 시리즈 보기

세마포어는 임베디드 시스템에서 공유 리소스 접근을 동기화하는 기초 메커니즘입니다. 태스크가 충돌 없이 안전하게 리소스 제어를 획득하고 해제할 수 있게 합니다.

세마포어 사용하기

Nucleus SE에서 세마포어 지원은 빌드 과정에서 활성화됩니다. 단일 애플리케이션에서 최대 16개 세마포어를 구성할 수 있습니다. 세마포어를 사용하지 않으면 관련 데이터 구조와 API 코드가 최종 바이너리에서 제외되어 풋프린트가 줄어듭니다.

세마포어는 단순히 8비트 카운터로, 여러 태스크가 안전하게 조작할 수 있도록 값이 보호됩니다. 태스크는 Obtain을 호출해 카운터를 감소시키고 Release로 증가시킵니다. 카운터가 0인 세마포어를 획득하려 하면 API 옵션과 시스템 구성에 따라 에러를 반환하거나 세마포어가 사용 가능해질 때까지 태스크를 일시 중단합니다.

세마포어 구성

세마포어 개수

세마포어는 nuse_config.h의 #define 문으로 정의됩니다. 핵심 매크로는 NUSE_SEMAPHORE_NUMBER로, 애플리케이션이 사용할 세마포어 슬롯 수를 지정합니다. 기본값은 0으로 세마포어 지원이 없음을 의미합니다. 유효 범위는 0~16입니다. 잘못된 값은 nuse_config_check.h(nuse_config.c를 통해 포함됨)가 생성하는 컴파일 타임 에러를 유발합니다.

NUSE_SEMAPHORE_NUMBER를 0이 아닌 값으로 설정하면 세마포어 서브시스템이 활성화되어 데이터 구조가 적절히 크기 조정되고 API 활성화 심볼이 처리됩니다.

API 활성화

각 Nucleus SE API 콜은 nuse_config.h의 전용 활성화 매크로로 보호됩니다. 세마포어 관련 심볼은:

기본적으로 모두 FALSE로 설정되어 해당 서비스 콜을 비활성화하고 구현을 빌드에서 제외합니다. 특정 API를 활성화하려면 매크로를 TRUE로 설정하세요.

기본 nuse_config.h 파일 발췌:

#define NUSE_SEMAPHORE_NUMBER 0 /* 시스템 내 세마포어 수 – 0‑16 */ #define NUSE_SEMAPHORE_OBTAIN FALSE /* 서비스 콜 인에이블러 */ #define NUSE_SEMAPHORE_RELEASE FALSE /* 서비스 콜 인에이블러 */ #define NUSE_SEMAPHORE_RESET FALSE /* 서비스 콜 인에이블러 */ #define NUSE_SEMAPHORE_INFORMATION FALSE /* 서비스 콜 인에이블러 */ #define NUSE_SEMAPHORE_COUNT FALSE /* 서비스 콜 인에이블러 */

세마포어가 구성되지 않은 상태에서 API를 활성화하면(단, NUSE_Semaphore_Count()는 항상 사용 가능) 컴파일 타임 에러가 발생합니다. 활성화되지 않은 API를 호출하면 구현이 생략되어 링크 타임 에러가 발생합니다.

세마포어 서비스 콜

Nucleus SE는 8가지 세마포어 관련 서비스 콜을 제공합니다. 처음 5개는 완전히 구현되었으며, 나머지 3개는 향후 확장을 위한 플레이스홀더입니다.

Obtain 및 Release 연산

핵심 세마포어 연산은 획득(감소)과 해제(증가)입니다. Nucleus RTOS는 선택적 일시 중단과 타임아웃이 있는 유연한 획득 API를 제공합니다. Nucleus SE는 이 동작을 반영하지만 태스크 일시 중단은 선택 사항이고 타임아웃은 지원하지 않습니다.

Nucleus RTOS Obtain API

프로토타입:

STATUS NU_Obtain_Semaphore(NU_SEMAPHORE *semaphore, UNSIGNED suspend);

매개변수:

semaphore – 세마포어 컨트롤 블록 포인터.

suspend – NU_NO_SUSPEND, NU_SUSPEND, 또는 타임아웃 값.

반환 값:

NU_SUCCESS – 작업 성공.

NU_UNAVAILABLE – 세마포어 값이 0.

NU_INVALID_SEMAPHORE – 유효하지 않은 세마포어 포인터.

NU_INVALID_SUSPEND – 비태스크 컨텍스트에서 일시 중단 시도.

NU_SEMAPHORE_WAS_RESET – 태스크 일시 중단 중 세마포어 리셋.

Nucleus SE Obtain API

프로토타입:

STATUS NUSE_Semaphore_Obtain(NUSE_SEMAPHORE semaphore, U8 suspend);

매개변수:

semaphore – 세마포어 인덱스.

suspend – NUSE_NO_SUSPEND 또는 NUSE_SUSPEND.

반환 값:

NUSE_SUCCESS – 작업 성공.

NUSE_UNAVAILABLE – 세마포어 값이 0.

NUSE_INVALID_SEMAPHORE – 유효하지 않은 세마포어 인덱스.

NUSE_INVALID_SUSPEND – 비태스크에서 일시 중단 시도 또는 블로킹 API 비활성화.

NUSE_SEMAPHORE_WAS_RESET – 일시 중단 중 세마포어 리셋.

구현 하이라이트

블로킹이 비활성화되면 구현은 카운터가 0이 아닌지 확인하고, 감소시킨 뒤 NUSE_SUCCESS 반환. 카운터가 0이면 NUSE_UNAVAILABLE 반환.

if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; } else { return_value = NUSE_UNAVAILABLE; }

블로킹이 활성화되면 루틴은 do…while 루프에 진입해 세마포어 획득을 시도. 카운터가 0이고 suspend가 NUSE_SUSPEND면 태스크를 블로킹. 해제 시 첫 대기 태스크가 깨어나고 루프가 획득을 재시도.

do { if (NUSE_Semaphore_Counter[semaphore] != 0) { NUSE_Semaphore_Counter[semaphore]--; return_value = NUSE_SUCCESS; suspend = NUSE_NO_SUSPEND; } else { if (suspend == NUSE_NO_SUSPEND) { return_value = NUSE_UNAVAILABLE; } else { NUSE_Semaphore_Blocking_Count[semaphore]++; NUSE_Suspend_Task(NUSE_Task_Active, semaphore << 4 | NUSE_SEMAPHORE_SUSPEND); return_value = NUSE_Task_Blocking_Return[NUSE_Task_Active]; if (return_value != NUSE_SUCCESS) { suspend = NUSE_NO_SUSPEND; } } } } while (suspend == NUSE_SUSPEND);

Nucleus RTOS Release API

프로토타입:

STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore);

매개변수:

semaphore – 세마포어 컨트롤 블록 포인터.

반환 값:

NU_SUCCESS – 작업 성공.

NU_INVALID_SEMAPHORE – 유효하지 않은 세마포어 포인터.

Nucleus SE Release API

프로토타입:

STATUS NUSE_Semaphore_Release(NUSE_SEMAPHORE semaphore);

매개변수:

semaphore – 세마포어 인덱스.

반환 값:

NUSE_SUCCESS – 작업 성공.

NUSE_INVALID_SEMAPHORE – 유효하지 않은 세마포어 인덱스.

NUSE_UNAVAILABLE – 카운터가 이미 255; 증가 불가.

구현 하이라이트

해제 루틴은 먼저 카운터가 최대값(255) 미만인지 확인. 그러면 카운터 증가. 블로킹이 활성화되고 이 세마포어에서 대기 중인 태스크가 있으면 첫 번째 태스크를 깨웁니다.

NUSE_CS_Enter(); if (NUSE_Semaphore_Counter[semaphore] < 255) { NUSE_Semaphore_Counter[semaphore]++; return_value = NUSE_SUCCESS; #if NUSE_BLOCKING_ENABLE if (NUSE_Semaphore_Blocking_Count[semaphore] != 0) { NUSE_Semaphore_Blocking_Count[semaphore]--; for (U8 index = 0; index < NUSE_TASK_NUMBER; index++) { if ((LONIB(NUSE_Task_Status[index]) == NUSE_SEMAPHORE_SUSPEND) && (HINIB(NUSE_Task_Status[index]) == semaphore)) { NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS; NUSE_Wake_Task(index); break; } } } #endif } else { return_value = NUSE_UNAVAILABLE; } NUSE_CS_Exit(); return return_value;

태스크가 세마포어에서 일시 중단된 경우, 해제 시 첫 번째 대기 태스크가 깨어나 실행을 계속합니다.

다음 기사에서는 이벤트 플래그 그룹과 관련 데이터 구조를 탐구할 예정입니다.


Colin Walls는 전자 산업에서 30년 이상의 경험을 가지고 있으며, 주로 임베디드 소프트웨어에 집중해 왔습니다. 컨퍼런스에서 자주 발표하고 기술 기사를 쓰며 임베디드 소프트웨어에 관한 두 권의 책을 저술했습니다. Colin은 Mentor Embedded(Mentor Graphics 임베디드 소프트웨어 부문)의 임베디드 소프트웨어 기술자이며 영국에 기반을 두고 있습니다. 블로그는 https://blogs.mentor.com/colinwalls. 이메일: colin_walls@mentor.com.


임베디드

  1. 캠 락(Cam Lock) 설명: 캐비닛을 은밀하게 보호하는 방법
  2. 아이 볼트(Eye Screws)란? 설계와 용도 전문가 가이드
  3. 스테인리스강 완벽 해설: 조성, 생산 공정, 글로벌 영향
  4. C# 기초: 입출력(Essential Input/Output) 완벽 가이드
  5. 자동차 서비스 어드바이저(서비스 라이터): 역할, 업무, 커리어 경로
  6. Nucleus SE의 메일박스: 구성 및 사용 실용 가이드
  7. Nucleus RTOS의 세마포어: 유틸리티 서비스 및 데이터 구조
  8. 이벤트 플래그 그룹 마스터하기: Nucleus RTOS/SE의 유틸리티 서비스와 데이터 구조
  9. Nucleus SE의 이벤트 플래그 그룹: 구성 및 API 사용 입문 가이드
  10. Nucleus SE 큐: 소개와 핵심 서비스 콜