개요
Xenomai에서 실시간 메시지 큐(message queue)는 하나의 태스크(task)가 다른 태스크에 데이터를 보내거나 받을 수 있도록 하는 실시간 IPC(inter-process communication)의 중요한 방법 중 하나이다. 메시지 큐는 여러 태스크가 서로 통신하고 데이터를 안전하게 주고받을 수 있는 방법을 제공하여 실시간 시스템에서 매우 중요하다.
특징
실시간 메시지 큐는 여러 가지 중요한 특성을 가지고 있다:
- FIFO 순서: 메시지를 전송한 순서대로 도착한다.
- 블로킹 및 논블로킹 모드: 송신 및 수신할 때 블로킹 혹은 논블로킹 모드로 사용할 수 있다.
- 우선순위 기반: 메시지가 큐에 도착하는 순서를 송신자의 우선순위를 기준으로 설정할 수 있다.
메시지 큐 생성
메시지 큐를 생성하기 위해 rt_queue_create
함수를 사용한다. 이 함수는 큐 객체와 큐의 속성을 초기화 한다.
#include <native/queue.h>
RT_QUEUE queue;
int err;
err = rt_queue_create(&queue, "MyQueue", Q_SIZE, Q_LIMIT, Q_FIFO);
if (err) {
// 에러 처리
}
여기서 중요한 매개변수는 다음과 같다:
&queue
: 큐 객체에 대한 포인터이다."MyQueue"
: 큐의 이름이다.Q_SIZE
: 큐의 크기(바이트)이다.Q_LIMIT
: 큐의 메시지 개수 제한이다.Q_FIFO
: 큐의 메시징 정책으로,Q_FIFO
는 FIFO 순서로 메시지를 처리한다.
메시지 보내기
메시지 큐에 메시지를 보내기 위해 rt_queue_send
함수를 사용한다.
int err;
err = rt_queue_send(&queue, message, message_size, Q_TIMEOUT);
if (err) {
// 에러 처리
}
여기서 중요한 매개변수는 다음과 같다:
&queue
: 대상 큐 객체에 대한 포인터이다.message
: 전송할 메시지에 대한 포인터이다.message_size
: 메시지의 크기(바이트)이다.Q_TIMEOUT
: 블로킹 모드에서 대기할 시간이다.
메시지 받기
메시지 큐에서 메시지를 받기 위해 rt_queue_receive
함수를 사용한다.
void *received_msg;
int err;
err = rt_queue_receive(&queue, &received_msg, TM_INFINITE);
if (err) {
// 에러 처리
} else {
// 메시지 처리
}
여기서 중요한 매개변수는 다음과 같다:
&queue
: 메시지를 받을 큐 객체에 대한 포인터이다.&received_msg
: 수신된 메시지에 대한 포인터이다.TM_INFINITE
: 무한대기 시간을 지정한다. 즉, 메시지가 올 때까지 블로킹된다.
메시지 큐 삭제
메시지 큐를 사용한 후에는 이를 삭제하여 자원을 해제해 주어야 한다. 이를 위해 rt_queue_delete
함수를 사용한다.
int err;
err = rt_queue_delete(&queue);
if (err) {
// 에러 처리
}
여기서 중요한 매개변수는 다음과 같다:
&queue
: 삭제할 큐 객체에 대한 포인터이다.
실용 예제
다음은 메시지 큐를 활용한 간단한 예제이다. 이 예제는 하나의 태스크가 메시지 큐에 메시지를 보내고, 다른 태스크가 해당 메시지를 받는 방식으로 작동한다.
송신 태스크
void sender_task(void *arg) {
char message[] = "Hello, Receiver";
int err;
while (1) {
err = rt_queue_send(&queue, message, sizeof(message), TM_INFINITE);
if (err) {
// 에러 처리
}
rt_task_sleep(1000000000); // 1초 대기
}
}
수신 태스크
void receiver_task(void *arg) {
void *received_msg;
int err;
while (1) {
err = rt_queue_receive(&queue, &received_msg, TM_INFINITE);
if (err) {
// 에러 처리
} else {
printf("Received message: %s\n", (char *)received_msg);
// 여기서 message를 사용 후 메모리 해제 필요
rt_queue_free(&queue, received_msg);
}
}
}
메인 함수
int main(void) {
int err;
// 큐 생성
err = rt_queue_create(&queue, "MessageQueue", 1024, 10, Q_FIFO);
if (err) {
// 에러 처리
return err;
}
// 송신 태스크 생성
RT_TASK sender;
err = rt_task_create(&sender, "Sender", 0, 50, 0);
if (err) {
// 에러 처리
return err;
}
rt_task_start(&sender, sender_task, NULL);
// 수신 태스크 생성
RT_TASK receiver;
err = rt_task_create(&receiver, "Receiver", 0, 50, 0);
if (err) {
// 에러 처리
return err;
}
rt_task_start(&receiver, receiver_task, NULL);
// 메인 스레드 대기
pause();
// 큐 삭제
rt_queue_delete(&queue);
return 0;
}
이 예제에서는 송신 태스크와 수신 태스크가 서로 다른 스레드에서 작동하며, 메시지 큐를 통해 통신하게 된다. sender_task
는 1초마다 메시지를 보내고, receiver_task
는 메시지를 수신하여 출력한다.
이러한 방식으로 실시간 메시지 큐를 활용하여 다양한 실시간 애플리케이션을 구현할 수 있다.