이번 시간에는 RTOS에 사용되는 Semaphore를 알아본다.
2개의 우선순위가 다른 태스크에서 세마포어를 사용하여 세마포어가 잘 동작하는지 알아볼 것이다.
9부에서는 태스크에 대해 알아보고, 10부에서 Semaphore를 본격적으로 들어갈테니 참고하도록 하자.
먼저 세마포어가 무엇인지 알아보자.
'공용자원에 동시 접근을 막는 것' 이라고 설명하면 이해가 쉬울 것 같다.
서로 다른 태스크가 공용자원(변수, 버퍼 등)에 '독점적' 사용권을 가지는 것이다.
태스크가 될 수도 있고 인터럽트가 될 수도 있다.
세마포어를 쉽게 열쇠라고 생각하면 된다.
예를 들어, 작업자 A가 열쇠를 가져오면(pend, take) 작업자 B는 공용자원에 접근할 수 없다.
작업자 A가 작업을 마치고 열쇠를 반납하면(post, give) 작업자 B는 공용자원에 접근할 수 있게 된다.
또한, 카운트 모드와 바이너리 모드가 있다.
바이너리 모드는 공용자원에 1개의 태스크 또는 인터럽트가 접근할 수 있다.
카운트 모드는 1개 이상의 태스크 또는 인터럽트가 접근할 수 있다.
바이너리 모드와 카운트 모드 둘다 실습에서 확인한다.
1. Semaphore_pend(Semaphore_Handle handle, UINT32 timeout)
세마포어(key)를 가져오는 함수이다.
이 때, timeout에는 BIOS_NO_WAIT 와 BIOS_WAIT_FOREVER 라는 2개의 옵션을 가진다.
BIOS_NO_WAIT 은 bios의 응답을 기다리지 않고 즉시 가져온다.
BIOS_WAIT_FOREVER 은 bios의 응답을 영원히 기다리는 것이다.
이 때, 세마포어(key)를 가져오게 되면, 카운트를 1만큼 감소한다.
함수가 실행될 때 세마포어(key)의 카운트가 0이라면, timeout 값에 따라 행동한다.
2. Semaphore_post( Semaphore_Handle handle)
세마포어(key)를 반납하는 함수이다.
공용자원에 대한 접근을 마치면 세마포어(key)를 반납해서 다른 작업자가 사용할 수 있게 해야 한다.
세마포어 카운트를 1만큼 증가한다.
숫자 개념으로 생각하면 쉽다.
세마포어 카운트가 0이 아닌 상태에서 Semaphore_pend() 함수가 실행되면 세마포어 카운트를 1만큼 감소한다.
Semaphore_post() 함수가 실행되면 세마포어 카운트를 1만큼 증가한다.
app.cfg 파일에 들어가서 세마포어 설정을 그림 1과 같이 해주자.
세마포어 타입을 Binary로 하는 경우엔 세마포어 카운트는 0과 1만 사용하게 된다.
따라서 초기 카운트를 0 또는 1로 해주자.
주의할 점은 초기 카운트를 0으로 하는 경우에는, BIOS_start() 함수 전에 Semaphore_post(Semaphore_Handle handle) 함수를 써주자.
(필자가 사용한 코드에서는 Semaphore_post(semaphore0) 이 될 것이다.)
초기화가 중요한 이유!
그림 2는 Semaphore_pend() 함수가 실행될 때 세마포어 카운트가 0인 경우를 보여준다.
timeout 값이 BIOS_WAIT_FOREVER 이므로 세마포어 카운트가 0이 아니게 될 때까지 무한정 기다리게 된다.
우선순위가 높은 TaskB가 먼저 실행되었고, 이 때의 세마포어 카운트가 0이었기에 무한정 기다리게 되어 Blocked 상태가 된다.
뒤이어 실행되는 TaskA에서도 세마포어 카운트가 0인 상태이므로 무한정 기다리게 된다.
우측 상단에서 Timer와 TaskA, TaskB의 실행 카운트를 보면 두 태스크는 1회만 실행된 것을 알 수 있다.
세마포어 카운트 값을 강제로 1로 만들어 주더라도 태스크는 무한정 대기 상태에서 벗어나지 않는다.
그림 3을 살펴보자.
Semaphore_pend() 함수가 실행되기 전에 세마포어 카운트는 1이다.
Semaphore_pend() 함수가 실행되면, 카운트를 1만큼 감소하여 0이 된다.
또한 그림 4와 같이 두 태스크에서 pend와 post를 나누어 담당할 수도 있다.
태스크가 3개인 예시도 확인해보자.
그림 5에는 TaskA, Task B, Task C가 순차적으로 실행되게끔 우선순위를 3, 2, 1로 설정했다.
TaskA에서 post를 하지 않은 상태에서 TaskB가 실행되며 pend를 하면 어떻게 될까?
이 경우엔 TaskB가 가장 마지막에 실행된다.
TaskA → TaskC → TaskB 순으로 실행되는 것이다.
여기서 좀더 나가보자.
그림 6과 같이 pend와 post를 각각 2개씩 태스크 4개에 나누어 놓으면?
TaskA → TaskC → TaskB → TaskD 순서로 실행된다.
pend가 포함되어 있는 태스크 중 우선순위가 높은 TaskA가 실행된다.
post가 포함되어 있는 태스크 중 우선순위가 가장 높은 TaskC가 그 다음으로 실행된다.
그 다음 설명은 말하지 않아도 알 것으로 생각한다.
세마포어 카운트의 초기값을 2로 한다면?
TaskA → TaskB → TaskC → TaskD 순으로 실행된다.
카운트에 따라서 알아서 실행 순서를 바꿔주는 셈이다!
심지어 우선순위가 다름에도!
[TMS320F28388D] SYS/BIOS 9부 - Task (2) | 2023.12.26 |
---|---|
[TMS320F28388D] SYS/BIOS 8부 - CPU1와 CM의 IPC 통신 (0) | 2023.12.21 |
[TMS320F28388D] SYS/BIOS 7부 - CLA 생성하기 with Hwi & Task (0) | 2023.09.02 |
[TMS320F28388D] SYS/BIOS 6부 - CLA 생성하기 + 되새김 (0) | 2023.08.28 |
[TMS320F28388D] SYS/BIOS 5부 - Hwi 생성하기 (0) | 2023.08.19 |