작업 간 조정 - FreeRTOS

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

작업 간 조정

이 단원에는 FreeRTOS 프리미티브에 대한 정보가 포함되어 있습니다.

대기열

대기열은 기본적인 형태의 작업 간 통신입니다. 대기열을 사용하여 작업 간이나 인터럽트와 작업 간에 메시지를 전송할 수 있습니다. 대부분의 경우 대기열은 스레드 세이프(thread-safe) FIFO(First In First Out) 버퍼로 사용되며, 새로운 데이터는 대기열의 뒤쪽으로 전송됩니다. 데이터가 대기열의 앞쪽으로 전송될 수도 있습니다. 메시지는 대기열을 통해 복사본으로 전송됩니다. 즉, 단순히 데이터에 대한 참조를 저장하지 않고 데이터(더 큰 버퍼에 대한 포인터일 수 있음)를 대기열에 복사합니다.

대기열 API는 블록 시간 지정을 허용합니다. 특정 작업이 빈 대기열에서 읽으려고 시도할 경우 대기열에서 데이터를 사용할 수 있거나 블록 시간이 경과할 때까지 해당 작업은 차단 상태로 전환됩니다. 다른 작업이 실행될 수 있도록 차단 상태인 작업은 CPU 시간을 사용하지 않습니다. 마찬가지로, 특정 작업이 전체 대기열에서 쓰려고 시도할 경우 대기열의 공간이 사용 가능해지거나 블록 시간이 경과할 때까지 해당 작업은 차단 상태로 전환됩니다. 동일한 대기열에 차단된 작업이 여러 개 있는 경우 우선 순위가 가장 높은 작업이 먼저 차단 해제됩니다.

다른 FreeRTOS 프리미티브(예: DTT(Direct-to-Task) 알림, 스트림 및 메시지 버퍼)는 다양한 일반 설계 시나리오에서 대기열에 대한 간단한 대안을 제공합니다.

세마포어 및 뮤텍스

FreeRTOS 커널은 상호 제외와 동기화의 목적으로 이진 세마포어, 계수 세마포어 및 뮤텍스를 제공합니다.

이진 세마포어는 두 개의 값만 가질 수 있습니다. 이 세마포어는 작업 간이나 작업과 인터럽트 간에 동기화를 구현하는 데 적합합니다. 계수 세마포어는 세 개 이상의 값을 가집니다. 계수 세마포어를 사용하면 여러 작업에서 리소스를 공유하거나 보다 복잡한 동기화 작업을 수행할 수 있습니다.

뮤텍스는 우선 순위 상속 메커니즘을 포함하는 이진 세마포어입니다. 즉, 우선 순위가 높은 작업이 현재 우선 순위가 낮은 작업에서 보유한 뮤텍스를 가져오려고 시도하는 동안 차단될 경우 토큰을 보유한 작업의 우선 순위가 차단된 작업의 우선 순위로 일시적으로 상승됩니다. 이 메커니즘은 우선 순위가 더 높은 작업이 차단 상태로 유지되는 시간을 최대한 단축하여 우선 순위 반전이 발생하는 것을 최소화하기 위해 설계되었습니다.

DTT 알림

작업 알림을 사용하면 세마포어와 같은 개별 통신 객체 없이 작업 간에 상호 작용하고, 인터럽트 서비스 루틴(ISR)과 동기화할 수 있습니다. 각 RTOS 작업에는 알림 내용(있는 경우)을 저장하는 데 사용되는 32비트 알림 값이 있습니다. RTOS 작업 알림은 수신 작업을 차단 해제하고 수신 작업의 알림 값을 선택적으로 업데이트할 수 있는 작업에 직접 전송되는 이벤트입니다.

RTOS 작업 알림을 이진 세마포어, 계수 세마포어 및 대기열(해당하는 경우)에 대한 더 빠르고 간단한 대안으로 사용할 수 있습니다. 작업 알림은 동일한 기능을 수행하는 데 사용될 수 있는 다른 FreeRTOS 기능에 비해 속도와 RAM 공간의 측면에서 이점이 있습니다. 하지만 작업 알림은 이벤트 수신자가 될 수 있는 작업이 하나뿐인 경우에만 사용될 수 있습니다.

스트림 버퍼

스트림 버퍼를 사용하면 바이트 스트림을 인터럽트 서비스 루틴에서 작업으로 또는 한 작업에서 다른 작업으로 전달할 수 있습니다. 바이트 스트림은 임의 길이를 가질 수 있으며 시작 또는 끝이 없어도 됩니다. 한 번에 쓰고 읽을 수 있는 바이트 수에 제한이 없습니다. 프로젝트에서 stream_buffer.c 소스 파일을 포함하여 스트림 버퍼 기능을 활성화합니다.

스트림 버퍼를 사용하면 버퍼에 쓰는 작업 또는 인터럽트 하나(라이터)와 버퍼에서 읽는 작업 또는 인터럽트 하나(리더)만 존재합니다. 라이터와 리더의 작업 또는 인터럽트 서비스 루틴이 달라도 되지만 여러 라이터 또는 리더가 존재하면 안 됩니다.

스트림 버퍼 구현에서는 DTT 알림을 사용합니다. 따라서 호출 작업을 차단 상태로 전환하는 스트림 버퍼 API를 호출하면 호출 작업의 알림 상태와 값이 변경될 수 있습니다.

데이터 전송

xStreamBufferSend()는 데이터를 작업 내 스트림 버퍼로 전송하는 데 사용되고, xStreamBufferSendFromISR()은 데이터를 인터럽트 서비스 루틴(ISR) 내 스트림 버퍼로 전송하는 데 사용됩니다.

xStreamBufferSend()는 블록 시간 지정을 허용합니다. xStreamBufferSend()가 스트림 버퍼에 쓰기 위해 0이 아닌 블록 시간으로 호출되고 버퍼가 꽉 찬 경우 공간을 사용할 수 있거나 블록 시간이 만료될 때까지 작업은 차단 상태로 전환됩니다.

sbSEND_COMPLETED()sbSEND_COMPLETED_FROM_ISR()은 스트림 버퍼에 데이터를 쓸 때 FreeRTOS API에 의해 내부적으로 호출되는 매크로입니다. 이 매크로는 업데이트된 스트림 버퍼의 핸들을 사용합니다. 두 매크로는 모두 스트림 버퍼에 데이터를 대기 중인 차단된 작업이 있는지 확인한 후, 있으면 해당 작업을 차단 상태에서 제거합니다.

FreeRTOSConfig.h에서 sbSEND_COMPLETED()의 자체 구현을 제공하여 이 기본 동작을 변경할 수 있습니다. 이 기능은 스트림 버퍼를 사용하여 멀티 코어 프로세서의 코어 간에 데이터를 전달할 때 유용합니다. 그러한 시나리오에서는 sbSEND_COMPLETED()를 구현하여 다른 CPU 코어에서 인터럽트를 생성한 다음 인터럽트의 서비스 루틴에서 xStreamBufferSendCompletedFromISR() API를 사용하여 데이터를 대기 중인 작업이 있는지 확인하고 필요한 경우 해당 작업을 차단 해제할 수 있습니다.

데이터 수신

xStreamBufferReceive()는 작업 내 스트림 버퍼에서 데이터를 읽는 데 사용되고, xStreamBufferReceiveFromISR()은 인터럽트 서비스 루틴(ISR) 내 스트림 버퍼에서 데이터를 읽는 데 사용됩니다.

xStreamBufferReceive()는 블록 시간 지정을 허용합니다. xStreamBufferReceive()가 스트림 버퍼에서 읽기 위해 0이 아닌 블록 시간으로 호출되고 버퍼가 비어 있는 경우 스트림 버퍼에서 지정된 양의 데이터를 사용할 수 있거나 블록 시간이 만료될 때까지 작업은 차단 상태로 전환됩니다.

작업이 차단 해제되기 전에 스트림 버퍼에 있어야 하는 데이터의 양을 스트림 버퍼의 트리거 수준이라고 합니다. 트리거 수준 10으로 차단된 작업은 버퍼에 10바이트 이상을 쓰거나 작업의 블록 시간이 만료될 때 차단 해제됩니다. 트리거 수준에 도달하기 전에 읽기 작업의 블록 시간이 만료될 경우 해당 작업은 버퍼에 기록된 데이터를 수신합니다. 작업의 트리거 수준을 1과 스트림 버퍼 크기 사이의 값으로 설정해야 합니다. 스트림 버퍼의 트리거 수준은 xStreamBufferCreate()를 호출할 때 설정됩니다. xStreamBufferSetTriggerLevel()를 호출하여 트리거 수준을 변경할 수 있습니다.

sbRECEIVE_COMPLETED()sbRECEIVE_COMPLETED_FROM_ISR()은 스트림 버퍼에서 데이터를 읽을 때 (FreeRTOS API에 의해 내부적으로) 호출되는 매크로입니다. 이 매크로는 버퍼 내에서 공간을 사용할 수 있을 때까지 대기하는 스트림 버퍼에 차단된 작업이 있는지 확인한 후 있는 경우 해당 작업을 차단 상태에서 제거합니다. FreeRTOSConfig.h에서 대체 구현을 제공하여 sbRECEIVE_COMPLETED()의 기본 동작을 변경할 수 있습니다.

메시지 버퍼

메시지 버퍼를 사용하면 인터럽트 서비스 루틴에서 작업으로 또는 한 작업에서 다른 작업으로 가변 길이의 별도 메시지를 전달할 수 있습니다. 예를 들어, 길이가 10, 20 및 123바이트인 메시지를 모두 동일한 메시지 버퍼에서 쓰고 읽을 수 있습니다. 10바이트 메시지는 개별 바이트가 아닌 10바이트 메시지로만 읽을 수 있습니다. 메시지 버퍼는 스트림 버퍼 구현을 기반으로 빌드됩니다. 프로젝트에서 stream_buffer.c 소스 파일을 포함하여 메시지 버퍼 기능을 활성화할 수 있습니다.

메시지 버퍼를 사용하면 버퍼에 쓰는 작업 또는 인터럽트 하나(라이터)와 버퍼에서 읽는 작업 또는 인터럽트 하나(리더)만 존재합니다. 라이터와 리더의 작업 또는 인터럽트 서비스 루틴이 달라도 되지만 여러 라이터 또는 리더가 존재하면 안 됩니다.

메시지 버퍼 구현에서는 DTT 알림을 사용합니다. 따라서 호출 작업을 차단 상태로 전환하는 스트림 버퍼 API를 호출하면 호출 작업의 알림 상태와 값이 변경될 수 있습니다.

메시지 버퍼를 사용하여 가변 크기 메시지를 처리하려면 각 메시지의 길이가 메시지보다 먼저 메시지 버퍼에 기록됩니다. 길이는 size_t 형식의 변수로 저장되며, 32바이트 아키텍처의 경우 일반적으로 4바이트입니다. 따라서 메시지 버퍼에 10바이트 메시지를 쓸 경우 실제로 14바이트의 버퍼 공간이 사용됩니다. 마찬가지로 메시지 버퍼에 100바이트 메시지를 쓸 경우 실제로 104바이트의 버퍼 공간이 사용됩니다.

데이터 전송

xMessageBufferSend()는 작업에서 메시지 버퍼로 전송하는 데 사용되고, xMessageBufferSendFromISR()은 인터럽트 서비스 루틴(ISR)에서 메시지 버퍼로 데이터를 전송하는 데 사용됩니다.

xMessageBufferSend()는 블록 시간 지정을 허용합니다. xMessageBufferSend()가 메시지 버퍼에 쓰기 위해 0이 아닌 블록 시간으로 호출되고 버퍼가 꽉 찬 경우 메시지 버퍼에서 공간을 사용할 수 있거나 블록 시간이 만료될 때까지 작업은 차단 상태로 전환됩니다.

sbSEND_COMPLETED()sbSEND_COMPLETED_FROM_ISR()은 스트림 버퍼에 데이터를 쓸 때 FreeRTOS API에 의해 내부적으로 호출되는 매크로입니다. 이 매크로는 단일 파라미터 즉, 업데이트된 스트림 버퍼의 핸들을 사용합니다. 두 매크로는 모두 스트림 버퍼에 데이터를 대기 중인 차단된 작업이 있는지 확인한 후, 있으면 해당 작업을 차단 상태에서 제거합니다.

FreeRTOSConfig.h에서 sbSEND_COMPLETED()의 자체 구현을 제공하여 이 기본 동작을 변경할 수 있습니다. 이 기능은 스트림 버퍼를 사용하여 멀티 코어 프로세서의 코어 간에 데이터를 전달할 때 유용합니다. 그러한 시나리오에서는 sbSEND_COMPLETED()를 구현하여 다른 CPU 코어에서 인터럽트를 생성한 다음 인터럽트의 서비스 루틴에서 xStreamBufferSendCompletedFromISR() API를 사용하여 데이터를 대기 중인 작업이 있는지 확인하고 필요한 경우 해당 작업을 차단 해제할 수 있습니다.

데이터 수신

xMessageBufferReceive()는 작업에서 메시지 버퍼의 데이터를 읽는 데 사용되고, xMessageBufferReceiveFromISR()은 인터럽트 서비스 루틴(ISR)에서 메시지 버퍼의 데이터를 읽는 데 사용됩니다. xMessageBufferReceive()는 블록 시간 지정을 허용합니다. xMessageBufferReceive()가 메시지 버퍼에서 읽기 위해 0이 아닌 블록 시간으로 호출되고 버퍼가 비어 있는 경우 데이터를 사용할 수 있거나 블록 시간이 만료될 때까지 작업은 차단 상태로 전환됩니다.

sbRECEIVE_COMPLETED()sbRECEIVE_COMPLETED_FROM_ISR()은 스트림 버퍼에서 데이터를 읽을 때 (FreeRTOS API에 의해 내부적으로) 호출되는 매크로입니다. 이 매크로는 버퍼 내에서 공간을 사용할 수 있을 때까지 대기하는 스트림 버퍼에 차단된 작업이 있는지 확인한 후 있는 경우 해당 작업을 차단 상태에서 제거합니다. FreeRTOSConfig.h에서 대체 구현을 제공하여 sbRECEIVE_COMPLETED()의 기본 동작을 변경할 수 있습니다.