크리에이티브 커먼즈 라이선스
Creative Commons License

I2C 의 최대 장점

하나의 통신라인으로 많은 장치와 통신을 할 수 있다.


하지만 여기서 문제.

내 MCU 는 3.3V 동작인데, 통신 하는 디바이스들이 1.8V, 5V 라면??


제일 먼저 떠오르는 생각! : Level Converter 를 달자!

하지만 이경우에 가격적인 측면도 문제고, 통신의 방향에 맞추어 스위칭을 해야하기때문에 여러모로 복잡하죠?


이럴때 N-Channel E-MOSFET 으로 간단하게 해결할수 있는 방법이 있습니다.

아래를 참고하시기를~

저는 보고 소름돋았음!


잘 안보이면 첨부파일 다운로드 할 것!



bi-directinal.pdf





저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License
굿 모닝 에브리 바디 ㅋㅋ

날씨가 굉장히 춥군요 ㅋ

여친님이 모닝콜 안했으면 아조 그냥 저세상 갈때까지 잠만 잘뻔했네 ㅋㅋ

오늘의 주제는 if 문과 switch 문의 최적화 입니다.

if 문과 switch 문의 차이점은 다 아시지요???

간단하게 한번 집고 넘어가자면,

다중 if 문을 쓸경우 (if, else if, else if ...... , else) 순차적으로 조건을 모두 비교해나가고,
switch 문은 비교 변수 인자와 비교를 해서 해당되는 case 로 바로 분기한다.


이해가 되실려나?? 

아 이게 안좋은 점이야 ㅋㅋ 분명히 최적화 글을 읽으려고 오신분 들은 저 정도 차이는 아실텐데 자꾸 자세히 쓰게되네 ㅠㅠ

Psudo Code 로 잠시 표현을 해보지요 

if(a==1)
else if(a==2)
else if(a==3)
....
else

와 같이 썼다고 가정해보지요. a == 100 까지 있다고 치공 ㅋㅋ

a ==99 가 들어왔어요 ㅋㅋ

그럼 바로  else if (a==99) 로 가지를 못하고, a==1 이였나??/ 거짓 ! 그럼 a==2야?? 아니 ㅋㅋ

이러면서 99 가 나올때까지 계속 비교를 한다는 것이지요 ㅋㅋ

하지만!!!

 switch 문은 a ==99 가 들어오면 99번에 해당하는 케이스로 바로 분기를 해 간다는 소리입니다.

즉! 차이점은?? 비교를 여러번 하느냐 한번만 하느냐의 차이라고 볼수 있습니다.

근데 여기서 하려고 했던 이야기는 이런것이 아니고 ㅋㅋㅋ

부득이 하게 위와 같은 다중 if 문을 쓸 경우에는 다중 분리 분기문을 이용해서 사용하면 오버헤드를 줄일수있습니다. 

예를 볼까요???

if(a==1)
else if(a==2)
....
else if(a==8)

과 같이 짜진 코드를 이진 분리해보면

if(a<=4)
{
if (a==1)
...
else if(a==4)
}
else
{
else if(a==5)
....
else if (a==8)
}
 
이런 식으로 짜면 확실히 비교의 횟수가 줄어들었지요????

switch 문 같은경우도 좀더 효율적으로 사용하기 위해서는

비교 인자를 문자로 사용할 때 보다 바로 숫자로 사용할때가 훨씬 좋습니다. 문자로 사용할때는 컴파일러가 형변환을 하게 되어서 시간이 조금 더 걸리거등여 ㅋㅋ

그리고 확률적으로 자주 사용될수 있는 케이스를 앞쪽에 위치시켜 주는 것도 한 방법이라 할 수 있겠습니다.
이것은 if 문에도 적용되는 이야기 입니다.

정리해 볼까용?

(1) 다중 분기문의 비교문에서 사용하는 연산은 한번만 수행하고, 이를 변수에 저장하여 사용한다.
(2) if 문 보다는 switch문이 속도, 메모리 적인 측면에서 모두 효율적이다.
(3) if 문으로 표현해야 한다면 선택될 확률이 높은 비교문을 앞쪽에 위치시기고, 이진 분리 분기 등과 같이 비교문의 실행을 줄이는 방법을 모색하도록 한다.
(4) 비교문과 같이 반복적으로 사용되는 데이터의 데이터 타입을 잘 선택한다.

등으로 정리 할 수 있겠군요.

이것 또한 자투리 지식으로 알아 둔다면 나중에 아는 척 하기 딱 좋겠지요? ㅋㅋㅋ

그럼 바이바바이
 
 
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License
제목이 이상한가??

ㅋㅋㅋ

어차피 이 글을 클릭하시는 분들은 C에대해 어느정도 자신감이 붙으신 분들이실테고 ㅋㅋㅋ

근데 ! 연산자와 ~연산자의 정확한 차이를 알고 계신감용???

헷갈리시는 분들 많으실겁니다 ㅋㅋㅋ

(1) ! 연산자

Logic NOT 입니다.
C 언어에서는 0 이 아닌 모든 수는 다 1로 생각하죠 ㅋㅋ LOGIC 적으로 말이에요 ㅋㅋ

단편적인 예로 if(3) 이렇게 써도 무조건 참으로 알고 돌자나영 ㅋ

! 연산자는 이렇듯 로직을 바꾸어주는 역할을 한답니다.

값을 바꾸는것이 아니라요 ㅋㅋ

예는 ~ 연산자와 함께 보여드리지요

(2) ~ 연산자

Bit Value NOT 입니다.

이해가 되시나영??

모든 수는 2진수로 저장됨은 알고 계시겠지요?/

각각의 비트에 들어갈수 있는 값은 1 아니면 0 입니다.

이 각각의 비트의 값을 반대로 바꾸는 것입니다.
 

(예제) 

 int main(void)
{
volatile unsigned int test_a = 10;
test_a = !test_a;


test_a =  ~test_a ;
}

(이해를 돕기 위해서 unsigned int 로했습니다. signed 로하면 부호가 바뀌겠지요?)

아래는 정답입니다.

 


아시겠지요????


여기서 제가 원래 이야기 하고 싶었던 부분은

LOGIC NOT 연산자의 최적화 입니다.

도대체 뭘 최적화 한다는 것이냐??

로직을 바꾸는데 ! 연산자를 쓸수도 있지만 ^ 연산자를 쓸수도 있습니다.
Exclusive OR 연산자 이지요~


1과 XOR 를 계속해주면 1,0,1,0 순서로 값이 반전됩니다.

과연 어떤 연산자를 써서 LOGIC NOT 을 하는 것이 더 빠를까요? ㅋㅋㅋ

일단 정답을 XOR 입니다 ㅋㅋ

아래는 비교하기 위한 코드이고 그 아래에서 어셈코드 보시죠 

int main(void)

{


volatile unsigned int test_a = 1;

test_a = !test_a;

test_a ^= 1;



[##_http://jbear.tistory.com/script/powerEditor/pages/1C%7Ccfile7.uf@196544404F0CE9551E0090.PNG%7Cwidth=%22363%22%20height=%22263%22%20alt=%22%22%20filename=%22dddddd.PNG%22%20filemime=%22image/jpeg%22%7C_##]

 역어셈 코드 잠시 알아볼까요??

MOVS(r4,#0x01) : r4 레지스터 1을 집어넣었군요

CBNZ : 0이거나 0이 아닌경우 비교 분기 (r4 는 피연산자가 들어가는 레지스터, 분기할 주소)
MOVS : r4 에 있던 값을  r0 레지스터로 옮기넹??
B : 다시 분기를 하는군요 0x080004C0 로 ㅋㅋ
MOVS : r0 에 0을 이동시켜놓고
MOV : r4 에다가 변화된 r0 를 이동시켜 놓으면서 ! 연산자 수행이 끝납니다

총 5개의 Instruction Set 을 돌았네용

아래는 ^ 연산자군요 ㅋㅋ

걍 EOR 하나죠? ㅋㅋ Exclusive OR 명령어 SET 을 가지고 있나바여 ㅋㅋ

아 참, 이 컴파일러는 uVision4 를 사용했습니다
Target CPU 는  ST 사에서 CortexM3 코어로 만든 STM32F103ZG 입니다

여튼 1개의 명령어로 끝나는군요 ㅋㅋ 

수행시간 차이를 볼까요??



! 연산자 : 4ns
^ 연산자 : 2ns

약 2배정도 차이가 나는군요~

물론 엄청 작은시간입니다 ㅋ 하지만 이런게 있다는것을 알아두는 것이 나쁘지는 않을듯 싶네요


저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License
연구실에 들어온지도 어언 1년이 넘어갔다.

이제서야 Cortex M3 와 말트고 지낼 친구가 된 기분이랄까???

사실 M3 를 사용함에 있어 크게 코드를 최적화 해야겠다라고 느낀적이 없다.

빠른 코어클락과 넉넉한 메모리 덕에 맘대로 짜도 다 돌아갔으니까 ㅋㅋ

하지만 임베디드 프로그래밍을 하는 사람으로써 코드 최적화 기법은 어느정도 알고 있어야하지 않을까??

지금 레퍼런스로 잡고 포스팅 하려는 책이 굉장히 쉽지만은 않다.

구현은 된다는 가정하에 얼마나 최적화해서 프로그래밍을 짜느냐에 초점이 맞추어졌는데, 쉬운게 이상하지.

(암 그렇고 말고 ㅋㅋㅋ)

정확하게 한번을 보는데 약 반년이라는 시간을 꾸준히 사용한것 같다.

그동안 내 실력도 늘어가면서 이해가 가지 않던 말 들이 이해가 가기도 하고 ㅋㅋ

아래는 내가 참조로 하여 포스팅할 책의 제목이다.

한빛 미디어에서 출판한 임베디드 프로그래밍 C코드 최적화 라는 책이다.

책에 나오는 내용을 글로만 읽으며 접근할때 잘 이해가 되지 않던 내용이 이 포스팅을 보면서,

필자 나름대로 해석한 생각까지 같이 읽을때 이해가 조금 더 쉬워지는 효과가 있었으면 한다.

물론 나도 이것을 정리하면서 나의 지식을 확고히 다지는 계기가 되었으면 하는 바램이 우선이지만 ㅋㅋ

책의 순서와 관계없이

내가 읽던 과정에서 정말 영감을 얻은 부분들을 위주로 기술해보려한다.

훗날 내가 내 포스팅을 보며 기억을 떠올릴 날들을 생각하며......

 
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License

마지막 강의 입니다.

그리 길지않은 마무리가 될것 같네요~

일전에 한번 Task 에 대해 간단하게 설명 드린적이 있습니다.

이놈의 Task 들은 CPU 를 자기 자신이 독점하고 있다고 생각하는 아주 멍청한 놈들이지요 ㅋㅋ 착각의 대장들 ㅋㅋ

이 테스크들은 5가지 상태를 가지고 있답니다 ㅋ

몰라도 문제없지만, 그래도 Kernel Programmer 라면 이정도는 한번 들어봤어야 하지 않나 싶어서 포스팅합니다.

(1) 수면상태 (Dormant)
(2) 준비상태 (Ready)
(3) 실행상태 (Running)
(4) 대기상태 (Waiting)
(5) 인터럽트 서비스 루틴 상태 (ISR)

ㅋㅋㅋ 다들 한번 씩 들어본 이름들이죠??

이 다섯가지 상태중에 한가지 상태를 가지면서 무한루프를 수행하고 있습니다.

수면상태가 좀 낯설수도 있는데요

테스크 자체는 상성되에 메모리에 존재하지만 커널에 등록이 되어있지 않은 상태라 커널이 서비스를 못해주는 상태를 말합니다.

준비상태는 "나 준비됐어요" 하고 스케쥴러에게 쳐다봐달라 하고 유혹하고 있는 상태입니다 ㅋㅋ

하지만 그 상황에서 CPU 는 다른 우선순위가 높은 테스크에게 서비스를 해주고 있는 상태이지요 ㅋㅋ

실행상태는 말그대로 실행되고 있는 상태이구요

대기상태는 OS Tick 을 이용해서 딜레이를 걸어놓았거나, 혹은 세마포어를 기다리고 있거나 하는 상황을 대기상태라고 부릅니다.

마지막 ISR 은 다들 아시겠지요? ㅋㅋ

아래는 uC/OS 에서 제공하는 OS 함수들이 각 테스크의 상태에 따라 어떻게 적용되는 지를 보여주는 블럭도입니다.





자 이렇게 RTOS 에 대한 포스팅을 마무리 하도록 하겠습니다

꾸준히 읽어주신분이 있을지 모르겠지만 이 글을 읽어주시는 분이 있다면 정말 감사할 따름입니다.

부족한 부분도 많지만, 훗날에라도 따로 추가할 만한 내용이 있드면 보충하도록 하겠습니다.


작은 정보이지만 정보를 주기위해 노력하는 사람들은 정보를 얻어가련 사람에 비해 수백배 이상의 노력을 기울이고 있습니다.
이런 사실을 알아주시고, 부족하지만 격려의 댓글을 달아주시면 더욱 힘이 나서 열심히 하는것이 포스팅하는 사람들의 습성이지요 ~ ㅋㅋ


그렇다고 댓들 달아달라고 징징대는것은 절대 아녀요 ㅠㅠㅠ

긴 글 읽어주셔서
감사합니다~ (꾸벅)
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License

이제 막바지입니다 ㅋㅋㅋ

지금 이야기할 주제는 리얼타임 커널이 자체적으로 가지고 있는 클럭틱 (Clock Tick) 에 관한 내용이에요 ㅋㅋ

클럭틱이란 정기적으로 일어나는 특별한 인터럽트 입니다. 이 정기적으로 일어나는 인터럽트가 리얼타일 OS 의 심장 박동이라고 할수 있지요 ㅋㅋ

이 인터럽트의 간격은 대부분의 커널이 프로그래머가 직접 조절 할 수 있도록 해놓습니다 ㅋ


보이시나요? ㅋㅋ

이것이 RTX_Kernel 이 제공하는 Config 창입니다 ㅋ

가운데 쪽에 보이시나요?? Timer tick Value[us] ㅋㅋㅋ

저는 10000 으로 현재 세팅을 했군요 ㅋㅋ

10ms 를 OS 한 틱으로 하겠다!!! 라고 설정한 것이랍니다 ㅋ

클럭틱 인터럽트는 커널로 하여금 클럭 틱 주기의 정수배 만큼 태스크를 지연시키고, 이벤트가 발생하기를 기다리는 태스크에게 타임아웃을 제공합니다 ㅋ

이 틱의 속도가 빠르면 빠를수록 CPU 에 더 많은 오버헤드가 걸리겠지요? ㅋㅋ

제가 사용하는 RTX Kernel 에서는 저 클럭틱을 이용한 딜레이 인터럽트를 제공하는 OS 제공 함수가

os_dly_wait(10) 이런식으로 쓴답니다 ~ ㅋㅋ

10틱 기다려라 라는 소리이지요 ~ ㅋㅋ

위와같이 세팅이 되어있다면, 태스크는 어플리케이션을 수행하다가 저 문장을 만나면 시피유의 점유권을 스케쥴러에게 양도하고 100ms 가 지난 후에 "I'm Ready" 이렇게 외치죠 ㅋㅋ

즉! 100ms 이후에 Ready List 에 들어가게 된다는 소리에요 ㅋㅋㅋ

하지만!!

여기가 중요합니다 ㅋㅋ 여기서 말하는 클럭틱의 시간이 진짜 타이머가 만들어내는 인터럽트처럼 완벽하게 정확하지가 않다는 것이지요~

예를 보시지요~


자 상위 우선순위 테스크와 ISR 이 1틱만큼 딜레이를 하려는 테스크보다 선행되어 실행되고 있습니다. 여기서 1틱을 20ms 로 설정했군요

이 태스크는 1틱만큼 딜레이를 시도하지만 우선순위 때문에 실제로는 불규칙적인 간격으로 실행되게 됩니다. 짧은 시간차이지만, 생각한대로 깔끔하게 제시간에 돌지는 못하는 군요???

이런 현상을 jitter 현상 라고 부른답니다.

그럼 우리는 이런 지터 현상을 어떻게 해결할수 있을까요? ㅋㅋㅋ

정답은 '돈' 입니다 ㅋㅋㅋ 비싸고 좋은 CPU 를 사용해서 작업을 더욱 빨르 끝내버려서 틱 인터럽트를 먹어버리는 현상을 줄여야하는 것이지요 ㅋㅋ

(1) MCU 의 클럭 속도를 높인다.
(2) 틱 인터럽트 사이의 시간을 늘린다.
(3) 태스크의 우선순위를 다시 지정한다.
(4) 플로팅 포인트 연산을 피하고 정수연산으로 변환한다.
(5) 코드 최적화를 수행한다.
(6) 시간이 중요한 코드는 어셈블리 언어로 프로그래밍한다.

정도의 해결방안을 줄수 있겠네요 ㅋㅋ

사실 OS 틱에 의존하여 매우 정확한 타이밍 마다 태스크를 돌게 하려는 발상은 발상 자체가 잘못된 것입니다.
다만 대부분 저정도의 수 밀리초 정도의 지터 현상이 전체 어플리케이션의 동작에 영향을 크게 미치지 않는 경우에 많이 사용하게 되지요 ㅋ

여러분이 사용하시는 윈도우즈 라는 OS 는 OS 틱이 1ms 입니다 ㅋㅋ

그래서 엄청 무거운 프로그램 돌리시거나, RAM Test 같은거 하거나 이렇때 윈도우 시계의 초침이 부자연스럽게 움직이는 경우를 경험해 보신적이 있으실거에요 ㅋㅋ

때에따라서 엄청 정확한 타이밍에 딱!!! 동작을 하게 만들어야하는 경우가 있습니다 ㅋㅋ

이때는 MCU 에 내장된 내장 타이머를 이용하여 Timer Overflow 를 이용해서 Interrupt 에서 처리를 하던지 혹은
이때 Interrupt 에서 해당 테스크로 이벤트를 날려주는 식으로 처리하시는 것이 올바른 방법이랍니다.

더욱 정확하게 확인을 하시기 위해서는 오실로스코프로 테스크 수행 틱을 정확하게 확인하면서 여러 방법을 시도하는 것이 좋지요 ㅋ

그럼 이번 강의는 여기서 줄이겠습니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License

아.. 제목부터가 굉장히 거부감 들게 생겼네 ㅋㅋ

이것은 뭐 엄청나게 외우고 확실하게 이해를 해야만 프로그래밍 할수 있는 것은 아닙니다 ㅋ

하지만 한번쯤은 들어보시고 생각을 해보시면 훗날 생길수 있는 문제들에 대해 접근할 때 유용하실 것이라 생각됩니다. ㅋㅋ 물론 이것때문에 문제가 된다면 오실로스코프로 조낸 찍어가면서 봐야하는 큰 문제이기 때문에 많이 접하실 일을 없을 것같아요 ㅋㅋㅋ

그리고 커널을 사용함에도 불구하고 저런 부분이 크리티컬한 문제로 다가오는 경우라면???

ㅋㅋ 엄청나게 대단한 일을 하시는 분이실 테니까 저보다 잘 아실테구요 ㅋㅋ

근데 왠만한 펌웨어에서는 크게 문제가 되질 않습니다 ㅋㅋ 또 내가 잘 몰라도 커널이 알아서 스케쥴링 잘 해줄것이라 믿어 의심치 않고 있어요 ㅋㅋ

사설은 여기까지 ㅋㅋ
이제 또 한번 설을 풀어 볼까요 ㅋㅋㅋ

( 아 요고 쓰고 2개만 더 쓰면 계획했던 RTOS 포스팅이 일단락 되는군요 ~ 긴 여정이였습니다)

(1) 인터럽트 지연시간 (Interrupt Latency)

간단합니다.

크리티컬 섹션을 처리하기 위해서 인터럽을 비활성화 해놓고 처리가 끝나면 다시 활성화 한다고 하였지요??

이렇게 인터럽트가 비활성화 되어있으면 돌아야하는 인터럽스 서비스 루틴이 실행이 안되고 지연이 되는 것이지요? ㅋㅋ

즉, 인터럽트가 비활성화 되어있음으로 인해 인터럽트가 지연되는 시간을 의미합니다.

인터럽트가 비활성화 된 최대 시간 + ISR 에서 최초 명령을 시작하려는 시간 = Interrup Latency

(2) 인터럽트 응답시간 (Interrupt Response)

초점은 같습니다. 하지만 한가지를 더 고려해 주는것이지요~

인터럽트 지연시간을 지나 인터럽트로 들어가는 시점까지가 아니라 실지로 ISR 에 사용자가 싸놓은 첫번째 코드를 실행할때가지 얼마의 시간이 걸렸는가??? 입니다.

뭔 차이가 있냐구요?/ ㅋㅋ

잘 생각해보세요~ ㅋㅋ 인터럽스 서비스 루틴의 코드를 실행하기 위해서는 원래 돌고있던 테스크에 해당되는 CPU 문맥을 저장해 놓아야 하잖아요 ㅋㅋ 그 시간까지 고려를 해서 생각한 시간이 인터럽트 응답시간입니다 ㅋ

즉!!!

인터럽트 응답시간 > 인터럽트 지연시간

의 공식은 항상 성립하는 참인 명제가 되는 것이지요~


인터럽트 지연시간 + CPU 문맥을 저장하는 시간 = Interrupt Response

가 되는 것입니다~

전경/배경 시스템과 비선점형 커널에서는 위와 같지만, 선점형 커널에서는 한가지가 더 추가됩니다.
위의 두개의 상황은 따로 커널이 제공하는 특별한 함수를 호출하지 않아도 큰 무리가 없지만, 선점형 커널에서는 ISR 이 진행중인것을 알려주어 커널로 하여금 인터럽트가 중첩되는 것을 알 수 있도록 해주는 함수를 실행해야 하거든요

그래서 아래와같이 공식이 살짝 바뀌어용~

인터럽트 지연시간 + CPU 가 문맥을 저장하는 시간 + 커널의 ISR 진입함수 실행시간
                                                                                           = Interrupt Response


(3) 인터럽트 복귀시간 (Interrupt Recovery)

이제 초점이 살짝 바뀝니다
지금까지는 인터럽트 진입 시점에 관해 논했다고 하면 이제 인터럽스 서비스 루틴이 끝나고 원래 실행 테스크나 배경 시스템으로 돌아오려는 시점에 대해서 논하게 됩니다.

ISR 이 끝난 시점에서 얼마나 빠르게 원래 돌던 코드로 돌아올수 있는지를 말하는 것이지요

반대로 생각하면 되겠지요??

CPU 가 문맥을 복구하는 시간 + 인터럽트로부터 복귀 명령을 수행하는 시간 = Interrupt Recovery

이것도 전경/배경 시스템 , 비선점형 커널에 해당되는 것이구요 선점형 커널에서는 하나의 시간이 더 필요하지요~
선점형 커널과 나머지 커널간의 차이점을 앞선 강의에서 이해하셨다면 답을 유추 하시는 분도 있으실 것이라 생각됩니다.

바로 !!!! 최상위 우선순위 태스크를 결정하는 시간 이지요~

최상위 우선순위 태스크를 결정하는 시간 + 최상위 우선순위의 Context Swtching 시간 + 인터럽트로부터 복귀 명령을 수행하는 시간 = Interrupt Recovery

이해가 되셨습니까???

한번만 딱 읽고 이해하시기는 약간 어려울 수도 있습니다.
하지만 앞선 내용을 찬찬히 이해하시고 한번더 읽어보시면 무리없이 이해하실 수가 있어요 ㅋㅋ

그래서 해당되는 내용의 그림을 요 아래쪽에 배치한것입니다~

그림보고 글을 읽다보니까 다 아는 것같긴 한데 확실히 머리에 안박히더라구용

그래서 위의 글을 먼저 읽으시고 그림을 보시고 "아 저쉐끼 그림을 왜 아래다 놔뒀어 그림보니 알아먹기 좋구만" 하시면서 위에서 다시한번 스윽 훑어보시고 살펴보시면 여러분의 지식이 되실것이라 믿어 의심치 않습니다 ㅋㅋㅋ

(아... 이러다 세상 모든 사람들이 나와 같은 수준의 지식을 갖겠군 ㅋㅋㅋ 그사이에 저는 더욱 발전해서 더 많은 내용을 포스팅 하겠습니다 ㅋㅋㅋ 스스로 자극을 받는 요론 자세 ㅋㅋㅋㅋ)



그럼 빠빠빠빠빠빠빠빠잉
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License
점점 고급으로 넘어가네요 ㅋㅋ

이번에 다룰 내용은 메일박스와 메세지 큐입니다.

헷갈리지 않게 메일박스와 메세지 큐를 간단하게 비교해보면요

"메시지 큐는 메일박스를 조기 묶는 밧줄로 줄줄줄 묶어 놓은 것이다"

정도로 정의할 수 있겠군요 ㅋㅋ

자 그렀다면 Let's Move~~~~

(1) 메일 박스

테스크간에 정보를 공유하기 위해서 가장 쉬운 방법은??? 전역변수를 사용하는 방법이지요~ ㅋㅋ
이럴 경우에 문제가 발생할 수 있다고 하였지요??

상호배제(Mutual Exclusion) 할때 많이 다뤘었자나요 ㅋㅋㅋ 이제는 알때도 됐어요 ㅋㅋㅋㅋ

공유자원에 접근하는 것이라면 모르겠지만, 한 테스크에서 다른 테스크로 데이터를 넘겨 주는 경우가 있을 수 있잖아요 ㅋ 그때 메세지를 전달하기 위해서 생긴 개념이에요 ㅋㅋ

메시지를 받아야 처리하는 테스크 입장에서는 메시지가 왔는지 안왔는지 주기적으로 살펴보는 Polling 작업을 하지 않아도 되겠지요??

 


즉, 커널이 굉장히 효율적으로 작동할수 있게 되는 것이지요 ~ ㅋㅋㅋ


요론 개념이랍니다 ~ ㅋㅋㅋ

보내고 싶은 정보가 있으면 메일 박스에다가 밀어 넣어주고~ (Post or Send) 메일 박스는 이 메시지를 기다리고 있는 테스크 (Wait or Pend) 에게 " 야 메시지 도착했어~~~ " 하고 알려주는 것이지요 ~ ㅋㅋ

우체부 같죠??
이 우체부 역할을 Kernel 이 해주는 것이랍니다.

메일박스는 일반적으로 포인터 사이즈 (Pointer-Size) 변수에요~ 테스크와 테스크 뿐만아니라 ISR 와 Task 사이의 메시지 통신에도 사용할수 있습니다. 또한 한개 이상의 Task 가 하나의 메세지를 수신 할수도 있지요~

메시지 수신을 원하는 테스카가 하나 이상인 경우에 대비해서 각 메일박스에는 Waiting List (대기목록) 이 있답니다. 빈 메일박스로부터 메시지를 기다리는 테스크는 메시지가 수신 될 때까지 대기상태가 되고, 메일 박스의 대기목록에 기록되지요.

메시지가 메일박스에 전달되면 스케쥴러는 메일박스를 기다리고 있는 테스크 중에 최상위 우선순위 테스크에게 전달되거나 커널에 따라서는 맨 첨에 메일박스를 요청한 테스크에게 서비스 해주기도 합니다. 이렇게 먼저 들어온놈에서 먼저 서비스 해주는것을 FIFO (First in Firtst Out) 이라고 합니다 ㅋㅋ 한국말로는 '선착순' 정도가 되겠네요 ㅋㅋ

일반적으로 커널은 다음과 같은 메일박스 서비스를 제공 합니다.

(1) Mailbox Init
(2) Mailbox Send (Post)
(3) Mailbox Wait (Pend)

이전에 배웠던 Binary Semaphore 를 이용하여 이 메일박스를 대신 할 수도 있지만 구지 그럴 필요는 없겠지요? ㅋ
제공해주는 좋은 기능을 사용하는 것이 좋으니까요 ㅋㅋ

메일박스와 메시지 큐에서 가장 기억해야 할 점은
보내는 정보가 내가 보내고 싶어하는 정보의 내용 자체 (Value) 가 아니라 정보가 저장되어 있는 메모리의 주소(Adress) 인 Pointer 라는 점을 확실하게 인지하시길 바랍니다 ~ ㅋㅋ


제가 만들어 놓은 Firmware 에서는 이렇게 메일박스를 이용합니다~

ECG, Body Impedance, Accelerometer, Temperature Sensor, Gyro-Sensor, Power Manager Chip 등의 여러값을 받아온답니다.

(1) 신호를 ADC 하고 End of Conversion 신호가 뜨면 DMA 를 Request 한 다음 DMA 가 Interrupt 를 요청한다.
(2) 이때 DMA Interrupt Service Routine 에서는 t_CopyData_task 에게 Event 를 던져 준다~

void DMA1_Channel1_IRQHandler(void){   
 ITStatus Status;
 Status = DMA_GetITStatus(DMA1_IT_TC1); 

 if(Status){  
  isr_evt_set(0x0001,t_CopyData_task);
  DMA_ClearITPendingBit(DMA1_IT_TC1);
 }
}

(3) t_CopyData_task 에서는 해당되는 메일박스를 생성하고 각각의 데이터를 해당되는 메일박스에 꽃아준다.

__task void tCopyData_task(void) {
 //pointer of Sand Message
 ACC_DATA *pSM_Acc_data;
 IMP_DATA *pSM_Imp_data;
 GYRO_DATA *pSM_Gyro_data;
 
 u32 cnt = 0;
    const u8 x=0, y=1, z=2; 
 u16 Gyro_x=0, Gyro_y=0, Gyro_z=0;

 os_mbx_init(ACC_MBX, sizeof(ACC_MBX));
 os_mbx_init (IMP_MBX, sizeof(IMP_MBX));
 os_mbx_init (GYRO_MBX, sizeof(GYRO_MBX));

 while (1) {
  os_evt_wait_or(0x0001, 0xffff);

  if(!(cnt%rACC_Sample_FREQ)){
  pSM_Acc_data = _alloc_box(AccDataPool);
  pSM_Acc_data->X = ADC1ConvertedValue[2];      
  pSM_Acc_data->Y = ADC1ConvertedValue[3];      
  pSM_Acc_data->Z = ADC1ConvertedValue[4]; 

  os_mbx_send (ACC_MBX, pSM_Acc_data, 0xFFFF);  

  Gyro_z = Gyro_Communication(x);
  Gyro_x = Gyro_Communication(y);
  Gyro_y = Gyro_Communication(z);

  pSM_Gyro_data = _alloc_box(GyroDataPool);
  pSM_Gyro_data->x_Gyro = Gyro_x;
  pSM_Gyro_data->y_Gyro = Gyro_y;
  pSM_Gyro_data->z_Gyro = Gyro_z;
  
  os_mbx_send (GYRO_MBX, pSM_Gyro_data,0xFFFF) ;
  
  }    

  pSM_Imp_data = _alloc_box(ImpDataPool);
  pSM_Imp_data->Impedance = ADC1ConvertedValue[0];
  pSM_Imp_data->Resp = ADC1ConvertedValue[1];     
  
  os_mbx_send (IMP_MBX, pSM_Imp_data, 0xFFFF);
               
  cnt++;
 }
}

(하나의 데이터가 여러개인 것도 있어서 memory pool 을 이용해서 메시지 큐 형태로 보내고 있습니다만 이해하시는게 크게 어려움은 없으실 것에요, 뭐 아래쪽에 설명한 메시지 큐를 이해하는데 도움도 되고 좋죠 머 ㅋ)

(4) 각각의 신호를 처리하는 테스크들은 이 메일박스를 wait 하고있다고 데이터를 넘겨받아 신호처리 하고 가공하여 2차 파라미터 값들을 얻어낸다~

요론 순서로 진행을 하고 있지요 ㅋㅋ

저기서도 데이터를 넘겨줄때 구조체의 메모리 주소를 넘겨주는 부분을 집중해서 보세요 ~ㅋㅋ

(2) 메시지 큐

길게 설명하지 않아도 될듯 합니다 ㅋ

한개 이상의 메시지를 한번에 묶어서 테스크로 보내기 위해서 사용되는 것이지요 ~ 메시지 큐는 기본적으로 메일박스의 배열 형태로 되어있답니다~

하는 짓도 메일박스와 거의 같아요~

여러개를 하나로 묶어서 보내야 되기 때문에 Memory Pool 이라는 것이 필요합니다~
초기에 선언을 해줘야하죠~

선언을 할때 들어갈 데이터 1개의 사이즈와 이런 데이터를 몇개나 담을 것인지 결정한답니다~

그럼 커널은 이 메시지 들이 밀려들어올때 Linked_List 형태로 묶어주지요~ ㅋㅋ

os_mbx_declare (ACC_MBX, 5);
_declare_box (AccDataPool,sizeof(ACC_DATA),5);/* Dynamic memory pool1 */

요론식으로 선언한답니다~

_init_box(AccDataPool, sizeof(AccDataPool), sizeof(ACC_DATA));

초기화는 요론식ㅋㅋㅋ

여기서 ACC_DATA 는

typedef struct {         /* Message object structure      */
 int X;                      /* AD result of measured X       */
 int Y;                      /* AD result of measured Y       */
 int Z;                      /* AD result of measured Z       */
} ACC_DATA;

요론식의 구조체 형태구요 ~ ㅋㅋㅋ

여기까지는 이해를 돕기위한 부분 코드이지만

나중에 Cortex M3 강의에서는 실질적으로 어떻게 구현을 하는지를 알려드릴테니까 지금은 개념만 이해하고 넘어가세용~ ㅋㅋㅋ

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License

세마세마 소리만 듣다보니 머리가 아푸시지요? ㅋㅋ

(리니지 본던 3층에 카르파 3인방중에 세마가 있지 않았나? ㅋㅋㅋ 세마의 모자 ㅋㅋㅋ)

세마포어를 이용하는 용도 여러개중에

카운팅 세마포어나 세마포어 은닉 이런 부분은 일단 생략하고 넘어가도록 할게요 ㅋㅋ

대신에 Deadlock 현상의 탈출과 세마포어를 이용한 랑데뷰 (동기화) 에 대해 소개하려 합니다.

(1) Deadlock (교착상태)

Deadly embrace 라고도 불리우는 교착상태는 두 태스크가 각자 다른 태스크에서 쓰고있는 자원을 무한정 기다리는 상태를 말합니다.

재미난 상황인데요 ㅋㅋ 예들 들어보지요 ㅋㅋ

테스크 1, 2번이 있습니다. 얘네들은 각각 리소스 1,2 두개가 모두 있어야 돌수가 있어요 ㅋ

테스크 1번은 리소스 1을 소유했습니다 ㅋㅋ
이때 테스크 2번은 리소스 2를 소유 했다고 생각해 보세요 ㅋ

그러면? 테스크 1번은 리소스 2번을 필요로 하고 이때 테스크 2번은 리소를 1번을 필요로 하겟네요? ㅋㅋ

아 이렇게 난감할때가 ㅋㅋ 어떻게 일이 진행 될 기미를 보이질 않습니다 ㅋ

테스크 1과 테스크 2 모두 더이상 진행이 불가해 지는것이지요

이런 상태를 Deadlock 이라고 부릅니다.

해결 방안은 아래와 같아요

(1) 프로세스를 진행하기 전에 필요한 모든 자원의 세마포어를 획득하도록 한다.
(2) 순서대로 자원을 획득하고 역순으로 자원을 양도한다.

대부분의 커널은 세마포어의 타임아웃을 지원합니다 ㅋ 일정 시간이 지났음에도 불구하고 필요한 세마가 모두 획득이 되질 않는다면 가지고 있는 세마를 모두 놓아 놓고 다시 경쟁을 붙이는 것이지요~

이런 식으로 해결 할수 있답니다~

(2) Synchronization (동기화)

세마포어를 플레그 처럼 사용하는 것이지요 ~ ㅋㅋ ISR 와 태슼, 혹은 태스크와 태스크를 동기화 할 수 있습니다 ㅋ

바로 Psudo Code 를 보여드리도록 하지요 ~

Task1()
{
task 2에게 신호를 보낸다
task 2로부터 신호를 기다린다
작업을 계속한다.
}

Task2()
{
task 1에게 신호를 보낸다
task 1 로 부터 신호를 기다린다.
작업을 계속한다.
}


이렇게 하면 Task 1과 Task 2 를 동기화 할 수 있지요? ㅋㅋ

그렇다고 진짜 동시에 도는 것은 절대로 아닙니다 ㅋㅋ

뇌를 장착할수 있는 곳은 1군데 밖에 없다고 하였지요? ㅋㅋ

라운드 로빈 도는것처럼 요 테스크 한번 조테스크 한번 사이좋게 빠르게 돌면 크게 보면 동기화해서
도는것처럼 보이자나요 ㅋㅋㅋ

정말로 페러럴 프로세싱을 원한다면 FPGA 쪽으로 가셔야지용 ㅋㅋㅋ

그럼 제가 직접 구현한 동기화 코드를 보실깝숑??

__task void task1(void)
{
 
 while(1)
 {
 
 os_sem_send(tsema1);
 os_sem_wait(tsema2,0x0F00);
 
 test_sem1++;
 }
}

__task void task2(void)
{
 
 while(1)
 {
 os_sem_send(tsema2);
 os_sem_wait(tsema1,0x0F00);
 test_sem2++;
 
 }
}

__task void Init(void)
{
 os_sem_init(tsema1,0);
 os_sem_init(tsema2,0);

 T_task1 = os_tsk_create(task1,10);
 T_task2 = os_tsk_create(task2,10);

 os_tsk_delete_self();
}

자 얼추 코드는 이렇습니다

위에서 설명한 것과 똑같이 짜놨지요??

예상대로라면 test_sem1 과 test_sem2 라는 변수가 사이좋게 1씩 차이나면서 올라가야합니다 ㅋㅋ

그럼 어디 그런지 함 보시죵

어때요 ㅋㅋ 싱크가 맞지용? ㅋㅋㅋ

이걸 다른말로 랑데뷰 라고도 부른답니다 ~ ㅋㅋ

한번씩들 해보셔요 ㅋㅋ

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
크리에이티브 커먼즈 라이선스
Creative Commons License

여러가지 태스크들이 서로 정보를 주고 받을수 있는 방법 중에 가장 쉬운 방법은 무엇일까요??

바로 공유 데이터를 이용하는 것입니다. 더욱 직관적으로 표현하자면 "전역변수" 를 사용하는 것이지요 ㅋㅋ

그럼 공유자원이란 무엇인가???

말그대로 여러가지 태스크에서 공동으로 사용, 접근할수 있는 모든 것입니다~

전역변수가 될수도 있고, Public 형의 함수나 클래스가 될수도 있고, 프린터와 같은 I/O 가 될수도 있죠.

여러 테스크들이 데이터와 자원을 공유하는 것은 좋은 일이지만, 그 과정에서 테스크 사이의 경쟁이나 다른 이유에 의해서 데이터가 손실되는 상황을 막아야 합니다.

모든 테스크가 접근하여 공유자원을 사용할수 있게 하지만, 한번에 하나씩만 사용할수 있도록 하겠다! 라는 개념이 바로 상호배제 (Mutual Exclusion) 입니다.

상호 배제를 구현하는 방법은 크게 4가지가 있습니다.

(1) 인터럽스 활성화 / 비 활성화 (Interrupt Enable / Disable)
(2) Test - And - Set (TAS) 수행
(3) 스케쥴러 비활성화 (Scheduler Lock / Unlock)
(4) 세마포어의 이용 (Semaphore) (혹은 뮤텍스 (Mutex) 의 이용)

아나 많기도 엄청나게 많네 ㅋㅋ 이런 거지같은게 ㅋㅋㅋ

한번에 쓸려면 엄청난 양이겠죠? ㅋㅋㅋ

(4) 번의 세마포어는 조금 더 쓰임새가 다양한 기능이므로 뒤에서 따로 자세히 다루도록 하고, 이번에는 세마포어가 무엇인지, 어떻게 상호배제에 이용하는지 정도만 간단하게 알아보겠습니다.

흠.. 벌써부터 양이 많아질것 같이 쫄리넹. 하지만 나도 졸업고사를 보긴해야하니 한번 정리한다 생각하고 기술해볼까나 ㅋㅋ

(1) 인터럽트 활성화 / 비활성화 (Interrupt Enable / Disable)

: 왠지 익숙하시죠?? 아니라구요???  머야 ! 장난하는거야? ㅋㅋㅋ 앞에 강의에서 살짝 언급드렸는데요 ㅋ
크.리.티.컬.섹.션 할때요! ㅋㅋㅋ USART TX Function 까지 예를 들어가면서  ㅠㅠㅠㅠㅠ

이럴때 배신감 느낀다 ㅋㅋㅋ 나 중,고등학교때 선생님들이 이런 기분이였을꺼야 ㅋㅋㅋ

이 방법은 상호 배제를 실행 할 수 있는 가장 손쉬운 방법중에 하나입니다.

왜일까요??? 스케쥴러를 이해하신 분들은 이해가 가실 것입니다. 동작하고 있는 테스크에서 CPU 점유율을 테스크자신의 의지가 아닌 외부의 힘에 의해 가져오려면 필수적으로 필요한것이 ISR (Interrupt Suervice Routine) 이라고 했습니다. 그것이 틱 인터럽트이던, 외부 인터럽트이던 무조건 인터럽트로 뛰어야만이 CPU 점유율이 스케쥴러로 넘어가고, 커널의 종류가 어떤 것인가에 따라 어느 Task 로 CPU 점유율을 넘겨줄 것인지가 결정되는 것이지요.

그렇다면~

공유자원을 Access 하고 있는 동안에 인터럽트를 꺼버리고, 이용이 다 끝난 이후에 인터럽트를 다시 켠다면요???

ㅋㅋㅋ 이제 감이 오시지요?? 다른 Task 나 ISR 에 의해서 공유자원이 동시에 경쟁되는 일을 원초적으로 있을수가 없습니다.

꼭 RTOS 기반이 아니라, 전경/배경 시스템에서도 마찬가지입니다. 배경 프로세스에서 공유자원을 접근하려 할때 의도치 않은 인터럽트에 의해 데이터가 변경된다면??? 배경 시스템 입장에서는 오염된 데이터를 얻게 되는 것이지요~

간단한 Psudo Code 는 아래와 같습니다.

 인터럽트 비활성화
 리소스 액세스 (공유자원 읽기 / 쓰기);
 인터럽트 활성화


여기서 주의해야할 점이 하나 있습니다.

인터럽트의 비활성화 기간이 너무 길면 시스템의 응답성에 영향을 줄수 있으므로 주의해야 합니다.  즉, 변수의 복사나 시간이 많이 걸리는 작업이라면 이 방법을 사용하는것을 다시 한번 생각해 보셔야 합나다.

좋은 커널은 얼마의 시간동안 인터럽트 비활성화를 할 수 있는지에 대해 정보를 제공합니다. 프로그램 할때 꼭 신경쓰시기 바랍니다.

(2) Test - And -Set (TAS)

약간 생소하지요??

커널을 사용할때는 거의 사용하지 않습니다~ 왜냐구요?? 세마포어가 있으니까요 ㅋㅋ

바꿔서 생각해보면, 전경 배경 시스템에서 전역변수를 이용해서 세마포어 같은것을 하나 만들어놓고 사용하는 것이랍니다. ㅋㅋ

그냥 프로그램 하는 자기 자신과의 약속이지요~

"함수가 자원을 액세스 하기 전에는 꼭 정해놓은 전역변수를 점검하고 그 변수의 값이 0일때만 그 자원에 엑세스 하겠다. 1일때는 절대로 접근을 시도조차 하지 않겠다"

ㅋㅋㅋㅋ

자기들만의 리그를 뛰고 있는거지요  머 ㅋㅋㅋ 프로그램하다보면 저런 비슷한거 많이 찾아볼수 있습니다 ㅋㅋㅋ

TAS 를 사용할때는 TAS 오퍼레이션이 인터럽트에 의해 선점이 되면 안되겠지요?? 그말인 즉슨, 꼭 수행하기 전에 인터럽트를 비활성화 해야한다는 소리입니당. ㅋㅋㅋ

여기서도 간단히 Psudo Code 를 써보면요

if ( 액세스 변수가 0 이면 )
{
변수를 1로 세팅한다.
인터럽트를 활성화 한다.
자원을 액세스 해서 사용한다.
인터럽트를 비활성화 환다.
액세스 변수를 0으로 세팅한다.
인터럽트를 활성화 시켜놓는다.
}
else
{
인터럽트 활성화 시킨다.    // 즉 자원에 액세스를 할수없다. 나중에 다시 시도한다.
}


정도가 되겠군요 ㅋㅋ

(3) 스케쥴러 비활성화

뭐 다들 비슷한 개념입니다.

비 선점형 커널에는 크게 관계없는 방법이겠네요 ~

이 방법을 사용하기 위해서는 전제 조건이 하나 필요합니다.

" ISR 과는 공유자원을 공유하지 않는다."

이 전제조건을 만족해야만 스케쥴러를 비활성화 시키는 것으로 우리가 의도하는 바를 이룰수 있죠.

개념은 이렇습니다.

"ISR 로 뛸 테면 뛰어라. 어차피 ISR 과는 공유자원을 공유하지 않으니까 ISR 이 공유자원을 훼손할 일은 없고, ISR 이 끝나고 나서 일하고 있던 테스크로 무조건 다시 CPU 점유권을 넘겨줘 버릴테니까 !!!! "

ㅋㅋㅋ

어디서 많이 보던 개념 아닌가요???

그렇습니다!!! 비선점형 커널이 하는 짓거리 지요?? ㅋㅋ

이 방법도 이론적으로 잘 동작하기는 합니다. ㅋㅋ

하지만 사용하고 있는 커널이 선점형 커널이라면, 구지 다른 좋은 방법이 많은데요 Mutual Exclusion 을 구현하기 위해 커널 고유의 특성을 변경할 필요는 없지 않을까요?/ ㅋㅋㅋ

그래서 이 방법은 부득이한 상황이 아니면 사용하지 않는것이 좋습니다 ㅋㅋ

사실 Scheduler Lock / Unlock OS 관련 함수를 저는 본적이 없군용 ㅋㅋㅋㅋ

여튼 여기도 Psudo Code

스케쥴러 락
공유자원 엑세스
스케쥴러 언락


ㅋㅋㅋㅋㅋ 단순하군 ㅋㅋㅋㅋ (이렇게 쓰면 프로그래밍 해주는 컴파일러를 만들면 대박일텐데요 ㅋㅋ 그죠?? ㅋ )

(4) 세마포어의 이용

 아  ㅋㅋㅋ 쓰다보니 거의 다 왔군요 ㅋㅋ 세마포어 ~

1960년 중반에 Edgser Diikstra 에 의해 발명 되었답니다 ㅋㅋㅋ (이름이 왜 저따위냐 ㅋㅋ)



대부분의 멀티태스킹 커널이 제공하는 프로토콜 메커니즘 이구요 꼭 상호 배제를 위해서만 사용되는 것은 아닙니다.

ㄱ) 공유자원 간의 액세스 제어 (Mutual Exclusion)
ㄴ) 이벤트의 발생을 알려줌 (Signaling)
ㄷ) 두 태스크 간의 동작을 동귀화 시킴 (Synchronization / Rendezvous)

정도로 볼 수 있겠군요 ㅋㅋ

일단 여기서는 ㄱ) 의 상황에 대해서만 간단하게 언급해볼깝숑 ㅋㅋㅋ

세마포어는 어떤 자원에 접근하기 위한 '열쇠' 와도 같은 개념입니다.

이 열쇠를 1개만 만들어 놓으면 "Binary Semaphor" 혹은 "Mutex" 라고 부르구요

열쇠는 좀 복사를 많이 해 놔서 여러개 만들어 놓으면 "Counting Semaphore" 라고 부릅니다.

우리는 ㄱ) 의 상황을 논의해야하니까 Binary Semaphore 를 사용해야 겠네요?? ㅋㅋ

세마포어는 생성되고 나면 Send , Waiting 의 두가지 작업을 할 수 있습니다.
혹은 Post, Pend 라고 부르기도 하지요 ~ 뭐 같은 개념이니까요 ㅋㅋ

Send 를 하면 세마포어의 숫자는 + 하게 됩니다. Wait (Pend) 해서 세마포어를 받게 되면 숫자는 - 하게 되지요 ㅋㅋ

이 숫자가 코드를 돌릴수 있는 횟수와 정확하게 일치 합니다.

즉, 키를 하나만 만들어 놓는다면??  한번에 한놈씩만 공유자원에 접근할수 있겠지요???

시작이 1개였는데 ㅋㅋㅋ 5놈이 기다리고 있던 10놈이 기다리고 있던 제일 먼저 어떤놈이 키를 가져가 버리면
세마포어 숫자가 0으로 바껴서 나머지놈들은 끝없이 기다려야만 하는 상황이거든요 ㅋㅋ

사용하던놈이 자원을 다 쓰고 Send (Post) 해야 갯수가 1로 늘어나고 다음놈이 가져다 쓸수 있는 상화ㅘㅇ이 되는 것입니다.

세마포어의 생성은 되어있는 상태가 가정하고 Psudo Code 를 작성해 보지요

세마포어 Wait (Pend)
공유자원 엑세스
세마포어 Send(Post)

간단하지요? ㅋㅋㅋ
일단 이렇게 단순하게 생각하시고 나머지 개념들은 뒤에서 다시 추가하도록 하셔요 ㅋㅋ

한번에 너무 많이 알려면 머리가 아푸니까요 ㅋㅋㅋ (대가리가 뽀개지니까요 라고 자연스럽게 썼다가 포스팅의 질을위해 급 바껐습니다 ㅋㅋㅋ)

그럼 빠이
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear


티스토리 툴바