Xenomai에서의 실시간 스레드

Xenomai는 리눅스 커널 상에서 동작하는 실시간 운영체제로, 실시간 스레드를 활용하여 엄격한 시간 요구사항을 충족시킨다. Xenomai의 실시간 스레드는 우선순위 기반 스케줄링을 통해 정해진 시간 내에 작업을 완료하도록 설계되었다.

실시간 스레드 생성

Xenomai에서 실시간 스레드를 생성하는 기본적인 방법은 rt_task_create 함수를 사용하는 것이다. 이 함수의 기본 시그니처는 다음과 같다:

int rt_task_create(
    RT_TASK *task,
    const char *name,
    int stack_size,
    int priority,
    int mode
);

각 매개변수의 의미는 다음과 같다: - task: 생성된 RT_TASK 구조체에 대한 포인터 - name: 스레드의 이름 - stack_size: 스레드의 스택 크기 (0이면 기본 스택 크기 사용) - priority: 스레드 우선순위 (높을수록 우선순위가 높음) - mode: 실행 모드 플래그

예제 코드

#include <native/task.h>
#include <native/timer.h>
#include <rtdk.h>

void demo_task(void *arg) {
    rt_printf("Hello from Xenomai real-time task!\n");
}

int main(int argc, char *argv[]) {
    RT_TASK demo_task_desc;

    rt_task_create(&demo_task_desc, "Demo Task", 0, 50, 0);
    rt_task_start(&demo_task_desc, &demo_task, NULL);

    pause();  // Halting main thread to maintain task execution

    return 0;
}

위 예제에서는 간단한 실시간 스레드를 생성하고 실행하는 방법을 보여준다. rt_task_create 함수가 성공하면 rt_task_start 함수로 스레드를 시작할 수 있다.

실시간 스레드 시작

스레드가 생성된 후에는 rt_task_start 함수를 사용하여 스레드를 시작한다:

int rt_task_start(
    RT_TASK *task,
    void (*task_func)(void *cookie),
    void *cookie
);

예제 코드

void demo_task(void *arg) {
    rt_printf("Running real-time task\n");
}

/* ... (생략된 코드) ... */

rt_task_start(&demo_task_desc, &demo_task, NULL);

실시간 스레드 종료

스레드가 더 이상 필요하지 않으면 rt_task_delete 함수를 이용하여 스레드를 삭제할 수 있다:

int rt_task_delete(RT_TASK *task);

예제 코드

rt_task_delete(&demo_task_desc);

스레드를 삭제하면 스레드와 관련된 자원이 모두 해제된다.

실시간 스레드 속성 및 제어

스레드의 우선순위와 모드를 동적으로 변경할 수 있다. rt_task_set_priorityrt_task_set_mode 함수를 활용한다.

우선순위 변경

int rt_task_set_priority(RT_TASK *task, int priority);

모드 변경

int rt_task_set_mode(
    int clrmask,
    int setmask,
    int *oldmode
);

예제 코드

rt_task_set_priority(&demo_task_desc, 60);

int oldmode;
rt_task_set_mode(0, T_LOCK, &oldmode);

위 코드는 특정 스레드의 우선순위를 60으로 설정하고, 모드를 변경하는 예제이다.

실시간 스레드 동기화

실시간 시스템에서 스레드 간 동기화는 매우 중요하다. Xenomai는 다양한 동기화 메커니즘을 제공한다. 대표적인 메커니즘으로는 뮤텍스, 세마포어, 메시지 큐가 있다.

뮤텍스 사용

뮤텍스는 여러 스레드에서 공통 자원에 대한 접근을 직렬화하는 동기화 도구이다. Xenomai에서는 RT_MUTEX을 사용한다.

#include <native/mutex.h>

RT_MUTEX mutex;

void task1(void *arg) {
    rt_mutex_acquire(&mutex, TM_INFINITE);
    rt_printf("Task 1 acquired mutex\n");
    rt_task_sleep(1000000000);  // 1 second
    rt_mutex_release(&mutex);
}

void task2(void *arg) {
    rt_mutex_acquire(&mutex, TM_INFINITE);
    rt_printf("Task 2 acquired mutex\n");
    rt_task_sleep(1000000000);  // 1 second
    rt_mutex_release(&mutex);
}

int main(int argc, char *argv[]) {
    RT_TASK task1_desc, task2_desc;

    rt_mutex_create(&mutex, "MyMutex");
    rt_task_create(&task1_desc, "Task1", 0, 50, 0);
    rt_task_create(&task2_desc, "Task2", 0, 50, 0);
    rt_task_start(&task1_desc, &task1, NULL);
    rt_task_start(&task2_desc, &task2, NULL);

    pause();  // Halting main thread

    rt_mutex_delete(&mutex);
    return 0;
}

세마포어 사용

세마포어는 일정한 개수의 자원에 대한 접근을 제어하는 동기화 도구이다. Xenomai에서는 RT_SEM을 사용한다.

#include <native/sem.h>

RT_SEM sem;

void semaphore_task(void *arg) {
    rt_sem_p(&sem, TM_INFINITE);
    rt_printf("Semaphore acquired by task\n");
    rt_task_sleep(1000000000);
    rt_sem_v(&sem);
}

int main(int argc, char *argv[]) {
    RT_TASK task1_desc, task2_desc;

    rt_sem_create(&sem, "MySem", 1, S_FIFO);
    rt_task_create(&task1_desc, "Task1", 0, 50, 0);
    rt_task_create(&task2_desc, "Task2", 0, 50, 0);
    rt_task_start(&task1_desc, &semaphore_task, NULL);
    rt_task_start(&task2_desc, &semaphore_task, NULL);

    pause();  // Halting main thread

    rt_sem_delete(&sem);
    return 0;
}

메시지 큐 사용

메시지 큐는 스레드 간 데이터를 전송하는 데 사용된다. Xenomai에서는 RT_QUEUE를 제공한다.

#include <native/queue.h>

#define QUEUE_SIZE 512

RT_QUEUE queue;

void sender_task(void *arg) {
    char message[] = "Hello from sender";
    rt_queue_write(&queue, &message, sizeof(message), Q_NORMAL);
    rt_printf("Message sent: %s\n", message);
}

void receiver_task(void *arg) {
    char *msg;
    int size = rt_queue_read(&queue, &msg, TM_INFINITE);
    if (size > 0) {
        rt_printf("Message received: %s\n", msg);
        rt_queue_free(&queue, msg);
    }
}

int main(int argc, char *argv[]) {
    RT_TASK sender_task_desc, receiver_task_desc;

    rt_queue_create(&queue, "MyQueue", QUEUE_SIZE, Q_UNLIMITED, Q_FIFO);
    rt_task_create(&sender_task_desc, "Sender", 0, 50, 0);
    rt_task_create(&receiver_task_desc, "Receiver", 0, 50, 0);
    rt_task_start(&sender_task_desc, &sender_task, NULL);
    rt_task_start(&receiver_task_desc, &receiver_task, NULL);

    pause();  // Halting main thread

    rt_queue_delete(&queue);
    return 0;
}

이와 같이 Xenomai에서 제공하는 다양한 동기화 메커니즘을 사용하여 실시간 스레드 간의 상호작용 및 자원 접근을 제어할 수 있다.