
각각의 태스크는 레지스터 값들이나 프로그램 카운터, 스택 등을 포함하는 고유의 콘텍스트를 가지고 있습니다. 그러나 다른 글로벌 변소, 정적 변수, 초기화된 변수, 초기화되지 않은 변수 같은 다른 데이터들은 시스템의 태스크 사이에서 공유됩니다. 윈도 또는 유닉스에 익숙한 사람이라면 RTOS에 있는 태스크는 프로세스보다는 스레드에 가깝다는 것을 알 수 있겠죠. 물론 전통적인 RTOS의 경우에 그렇다는 얘기입니다. 많이 쓰는 리눅스나 윈도우 CE는 데스크톱 운영체제의 축소형이라서 프로세스도 가지고 있고 스레드도 가지고 있습니다. 프로세스에서 스레드들을 사용하기 때문에 태스크는 프로세스에 더 가깝다고 할 수 있겠죠.
RTOS는 일반적으로 다른 태스크에서는 사용할 수 없는 독자적인 데이터 구졸르 보입니다.
태스크들 사이에서 데이터를 공유할 수 있는터라 데이터를 하나의 태스크에서 다른 태스크로 이동시키는 일을 쉽습니다. 두 태스크가 단지 같은 변수에 접근하면 해결됩니다. 변수가 선언된 같은 모듈 안에서 두 태스크를 사용하거나 한 태스크에서 변수를 선언한 다음에 다른 태스크에서 exrern 키워드를 사용해서 선언함으로써 데이터 공유를 달성할 수 있지요.
[공유 데이터 문제]
예를 들어보면 버그가 있는 불행히 버그가 있는 코드가 있다고 합시다. 시스템에서 인터럽트 루틴이 태스크 코드와 데이터를 공유하기 때문에 버그들이 발생하는 문제에 대해서 언젠가 말했던 적이 있는데 여기에서는 두 태스크는 데이터를 공유하는 상황이지만 이전에 봤던 거의 동일한 종류의 버그가 다시 나타납니다. RTOS는 어떤 순간에 a를 중지시키고 b를 실행시킬 수 있는 능력이 있지요. 이것은 좋은 응답성을 얻기 위해서 해야만 하는 일이라는 것을 기억해야 합니다. 다만 RTOS는 a에서 아토믹 명령어가 아닐 때 특정 배열에 대한 데이터를 설정하다가 중지시킬 수 있고, b는 반만 바뀐 데이터를 읽을 수 있습니다.
다음에 이런 문제를 해결할 수 있는 툴들에 대해 다루겠지만 해결책을 보기 전에 이 기묘한 현상에 대해서 더 얘기해보겠습니다. 다른 예를 살펴보면 t1과 t2 둘다 vCountErrors 함수를 호출합니다. RTOS에서는 이렇게 하는 것이 전혀 이상한 일이 아닙니다. 어떤 아니면 모든 태스크들은 필요한 만큼의 서브루틴을 공유할 수 있어요. 그러나 잠재적인 버그가 있을 수 있습니다. 이 예제의 어려운 점은 t1과 t2가 둘 다 함수를 부르고 있고 변수를 공유한다는 점에 있습니다. 공유 데이터 문제의 희생양이 되는 문제가 발생하는 것이죠.
[재진입]
함수가 재진입이 가능한지 결정하기 위해서는 몇가지 규칙을 적용할 수 있습니다.
1) 재진입이 가능한 함수는 변수들이 그 함수를 호출한 태스크의 스택에 저장되거나 또는 그 태스크만 유일하게 사용하는 경우를 제외하고는, 아토믹하지 않은 방법으로 변수들을 사용하지 않음
2) 재진입이 가능한 함수는 재진입이 가능한 함수가 아닌 어떠한 함수도 호출하지 않음
3) 재진입이 가능한 함수는 아토믹하지 않은 방법으로 하드웨어를 사용하지 않음
[C 언어의 변수 저장의 복습]
재진입 가능성을 더 잘 이해하고, 위에서 특히 1번 룰을 정확히 이해하기 위해서는 먼저 C 컴파일러가 변수를 어디에 저장하는 지를 알아야만 합니다. C 언어에 대해서 달인이라고 생각한다면 다음의 변수가 메모리에 어디에 저장되는지에 대한 내용은 건너뛰어도 됩니다. 아직 도가 트지 못했다면 다음 질문에 대해서 생각해봅시다. 어떤 변수가 스택에 저장되고 어떤 변수가 메모리의 고정된 위치에 저장될까요? 또는 이 스트링은 어디에 저장될까요? vPointer, parm_ptr 등등 그에 대한 답을 보겠습니다.
- static_int 메모리상에 고정된 위치에 있기 때문에 이 함수를 부르는 태스크들 사이에서 공유됩니다.
- public_int 역시 마찬가지입니다. 유일한 차이는 다른 파일에 존재하는 C 함수들이 여기에는 접근 할 수 있지만 st에는 접근할 수 없다는 것입니다. 물론 시스템의 어떤 모듈에 있는 무슨 함수도 이 변수를 이용할 수 있기 때문에, 여러 태스크들이 이 변수를 공유하지 않게 하는 것이 더 어렵다는 것을 의미합니다.
- inintalized 또 똑같습니다. 초기값은 변수가 어디에 저장되는지에 전혀를 영향을 미치지 않습니다.
- string, 이 스트링은 어디에 저장될까? 이하동문입니다.
- vPointer 포인터 자체는 메모리의 고정된 위치에 있기 때문에 공유 변수입니다. 만약 함수가 가리키는 데이터를 사용하거나 값을 변경한다면, 그 함수를 호출하는 태스크들은 역시 그러한 값을 공유하는 것이 됩니다.
- parm 스택에 달려있습니다. 각각의 태스크는 독자적인 스택을 가지고 있기 때문에, 하나 이상의 태스크가 함수를 호출할 때마다 parm은 각각 다른 위치에 있게 됩니다. 얼마나 많은 ㅐ스크가 함수를 호출하느냐와 관계없이 parm 변수는 문제가 되지 않습니다.
- parm_ptr 똑같죠. 스택에 있습니다. 그러므로 함수는 문제없이 값을 변경시킬 수 잇습니다. 그러나, 함수가 가리키는 값을 사용하거나 변경시킨다면 문제가 발생하는지 안 하는지는 그 값이 어디에 저장되는지에 달려 있습니다. 함수를 호출하는 코드를 관찰해서 모든 태스크의 값이 다르다면 아무 문제가 없습니다. 두 개의 태스크들이 같은 값을 가지고 있다면 분명히 문제를 발생시킬 거예요.
- static_local 메모리에 고정된 위치에 있습니다. 이 변수와 int의 차이점은 같은 C 파일 안에 있는 다른 함수들은 변수를 사용할 수 있지만 local 은 단지 그 함수에서만 사용될 수 있다는 점입니다.
[재진입의 회색 지대]
재진입 가능한 함수와 그렇지 못한 함수 사이에 약간의 회색 지대가 존재합니다. 한 개의 명령어를 가지고 있는 함수의 성능이 필요하고 80x86을 사용하고 있고 많은 주석을 붙일 경우, vCountErrors를 이러한 방식으로 작성해서 해결할 수 있습니다. 하지만 이 코드가 다음 버전의 컴파일러 또는 나중에 포팅하게 될지도 모를 다른 마이크로프로세서에서도 잘 작동할지는 누구도 모릅니다. vCountErrors를 이러한 식으로 코드를 작성하게 되면, 지뢰를 시스템에 심고서 그저 폭발하기를 기다리는 것과 다를 바 없죠. 따라서 vConterErrors 가 재진입이 가능하게 하려면 다른 방법 중 하나를 사용해야만 합니다.
참고)
알토스의 기본단위 태스크(Task)를 알아보자
알토스로 작성되는 소프트웨어의 가장 기본적인 단위는 태스크입니다. 태스크를 작성하는 일은 매우 쉬운 편인데요, 대부분의 RTOS에서 태스크는 단순히 서브루틴에 불과합니다. 프로그램의 어�
ppojjaknews.tistory.com
'IT > 임베디드 시스템' 카테고리의 다른 글
세마포어의 용도/종류/문제 그리고 공유데이터 보호 방법 (0) | 2020.06.03 |
---|---|
RTOS 문제 해결 툴 - 세마포어 (0) | 2020.06.03 |
알토스의 기본단위 태스크(Task)를 알아보자 (0) | 2020.06.03 |
RTOS에 대한 기본적인 이해와 개요 (0) | 2020.06.03 |
임베디드 소프트웨어 (2) - 펑션스케줄링 구조, RTOS 구조 (0) | 2020.06.03 |
댓글