# Xenomai 세마포어와 뮤텍스

### Xenomai 세마포어

#### 세마포어란 무엇인가

세마포어는 동기화 도구로, 여러 스레드가 자원을 안전하게 공유할 수 있도록 도와준다. 쉽게 말해, 세마포어는 특정 자원에 접근하려는 스레드의 수를 제어하는 역할을 한다.

#### 세마포어의 작동 원리

세마포어는 내부적으로 카운터를 유지하며, 이 카운터는 잠금 및 해제 시 증가하거나 감소한다.

* **리소스 접근 (P 연산)**:

$$
P(s) \text{ 즉 } \text{wait}(s):
\begin{cases}
\text{if } (s > 0) \\
\quad s \leftarrow s - 1 \\
\text{else} \\
\quad \text{block the thread}
\end{cases}
$$

* **리소스 해제 (V 연산)**:

$$
V(s) \text{ 즉 } \text{signal}(s):
\begin{cases}
s \leftarrow s + 1 \\
\text{if any threads are blocked} \\
\quad \text{unblock a single thread}
\end{cases}
$$

#### Xenomai에서의 세마포어 사용법

Xenomai는 기본적으로 POSIX 세마포어 API를 많이 따른다. 주요 함수는 다음과 같다:

* `rt_sem_p()`: 세마포어 대기 (P 연산)
* `rt_sem_v()`: 세마포어 해제 (V 연산)
* `rt_sem_create()`: 세마포어 생성
* `rt_sem_delete()`: 세마포어 삭제

**세마포어 예제 코드**

```c
#include <native/sem.h>
#include <native/task.h>
#include <rtdk.h>

RT_SEM semaphore;

void task1(void *arg) {
    rt_task_set_periodic(NULL, TM_NOW, 1e5); // 주기 설정
    while(1) {
        rt_sem_p(&semaphore, TM_INFINITE); // 세마포어 잠금
        rt_printf("Task 1: Critical section\n");
        rt_sem_v(&semaphore); // 세마포어 해제
        rt_task_wait_period(NULL);
    }
}

void task2(void *arg) {
    rt_task_set_periodic(NULL, TM_NOW, 1e5); // 주기 설정
    while(1) {
        rt_sem_p(&semaphore, TM_INFINITE); // 세마포어 잠금
        rt_printf("Task 2: Critical section\n");
        rt_sem_v(&semaphore); // 세마포어 해제
        rt_task_wait_period(NULL);
    }
}

int main(int argc, char* argv[]) {
    rt_sem_create(&semaphore, "MySemaphore", 1, S_PRIO);
    rt_task_create(&task1_t, "Task 1", 0, 50, 0);
    rt_task_create(&task2_t, "Task 2", 0, 50, 0);
    rt_task_start(&task1_t, &task1, NULL);
    rt_task_start(&task2_t, &task2, NULL);
    pause();
    rt_sem_delete(&semaphore);
    return 0;
}
```

### Xenomai 뮤텍스

#### 뮤텍스란 무엇인가

뮤텍스(Mutex)는 Mutual Exclusion의 약자로, 주요 기능은 한 번에 하나의 스레드만 특정 자원에 접근하도록 보장하는 것이다. 뮤텍스는 잠금을 얻은 스레드만 자원을 사용할 수 있으며, 다른 스레드는 잠금이 해제될 때까지 대기한다.

#### 뮤텍스의 작동 원리

뮤텍스는 두 가지 기본 상태인 '잠김'(Locked)과 '잠금 해제'(Unlocked) 상태를 갖는다.

* **잠금 (Lock)**: 자원을 사용하려는 스레드는 뮤텍스를 잠금으로 설정한다.
  * 만약 뮤텍스가 이미 잠긴 상태라면, 해당 스레드는 블록된다.
* **잠금 해제 (Unlock)**: 자원을 다 사용한 후, 잠금을 해제하여 다른 스레드가 자원을 사용하도록 한다.

#### Xenomai에서의 뮤텍스 사용법

Xenomai는 기본적으로 POSIX 뮤텍스 API를 많이 따른다. 주요 함수는 다음과 같다:

* `rt_mutex_create()`: 뮤텍스 생성
* `rt_mutex_delete()`: 뮤텍스 삭제
* `rt_mutex_acquire()`: 뮤텍스 잠금
* `rt_mutex_release()`: 뮤텍스 잠금 해제

**뮤텍스 예제 코드**

```c
#include <native/mutex.h>
#include <native/task.h>
#include <rtdk.h>

RT_MUTEX mutex;

void task1(void *arg) {
    rt_task_set_periodic(NULL, TM_NOW, 1e5); // 주기 설정
    while(1) {
        rt_mutex_acquire(&mutex, TM_INFINITE); // 뮤텍스 잠금
        rt_printf("Task 1: Critical section\n");
        rt_mutex_release(&mutex); // 뮤텍스 해제
        rt_task_wait_period(NULL);
    }
}

void task2(void *arg) {
    rt_task_set_periodic(NULL, TM_NOW, 1e5); // 주기 설정
    while(1) {
        rt_mutex_acquire(&mutex, TM_INFINITE); // 뮤텍스 잠금
        rt_printf("Task 2: Critical section\n");
        rt_mutex_release(&mutex); // 뮤텍스 해제
        rt_task_wait_period(NULL);
    }
}

int main(int argc, char* argv[]) {
    rt_mutex_create(&mutex, "MyMutex");
    rt_task_create(&task1_t, "Task 1", 0, 50, 0);
    rt_task_create(&task2_t, "Task 2", 0, 50, 0);
    rt_task_start(&task1_t, &task1, NULL);
    rt_task_start(&task2_t, &task2, NULL);
    pause();
    rt_mutex_delete(&mutex);
    return 0;
}
```

#### 세마포어와 뮤텍스의 차이점

* **세마포어**:
  * 일반적으로 여러 개의 스레드가 동시에 자원을 사용할 수 있도록 한다.
  * 카운터를 통해 자원 접근 허용 수를 관리.
* **뮤텍스**:
  * 한 번에 단 하나의 스레드만 자원에 접근할 수 있도록 보장.
  * 뮤텍스를 잠금 획득한 스레드만 자원에 접근 가능.

***

Xenomai 활용 시, 세마포어와 뮤텍스를 적절히 사용하는 것이 매우 중요하다. 각각의 특징과 작동 원리를 이해하고, 제시된 예제 코드를 바탕으로 응용하면, 실시간 운영 체제에서 안전하고 효율적인 스레드 동기화를 구현할 수 있다.
