마지막 강의 입니다.

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

일전에 한번 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

이제 막바지입니다 ㅋㅋㅋ

지금 이야기할 주제는 리얼타임 커널이 자체적으로 가지고 있는 클럭틱 (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

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

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

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

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

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

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

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

( 아 요고 쓰고 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
점점 고급으로 넘어가네요 ㅋㅋ

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

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

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

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

자 그렀다면 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

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

(리니지 본던 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

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

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

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

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

전역변수가 될수도 있고, 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

선점형 커널은 ISR 에서 복귀 한 후에 스케쥴러가 CPU 점유권을 최상위 우선순위를 갖는 테스크에게 넘겨준다고 했었습니다.

그!런!데!!!!!!

도대체 이놈의 스케쥴러가 어떻게 최상위 우선순위 Task 를 검출해 낼까요?

여러가지 알고리즘이 있을수 있지만, 제가 공부하는 uC/OS 에서 소개하는 알고리즘을 하나 소개해 드리지요 ㅋ

컴마스터인 신태민 교수님께서 OS 도입 초창기에 이 알고리즘을 보신 후에 감탄을 금치 못하셨다는 후문이 ㅋㅋ

우선순위가 255까지 있는 커널이 있다고 가정합니다.

낮은 숫자가 우선순위가 높다고 가정하고 가장 높은 우선순위를 찾아봅시다.

혹자는 이렇게 생각 할 수 도 있겠지요.

"야 그거 Ready 상태에 있는 Task 다 검색해서 정렬 쭈욱 한다음에 제일 높은 우선순위 찾으면 되는거 아냐?"

그렇게 해도 됩니다.

다만, 여기서 소개할려는 알고리즘이 굉장히 Simple 하고 멋있고 세련되고 빠른 방법이기에 소개하려는 것이지요 ㅋ

(1) 각 우선순위를 8열로 나누어 정렬한다
(2) OSRdyGrp 이라는 1byte 변수를 만들고, 이 변수의 각 비트는 각각의 행을 대표한다.
(3) 각 그룹의 8개의 Task 들 중에서 하나라도 Ready 상태가 되면 OSRdyGrp 의 해당 비트를 1 로 Set 한다.
     이 변수를 만들기위해 검색을 하는 과정에서 각 그룹별로도 각각의 우선순위에 해당하는 Task 가 Ready 상태이면 1, 아니면 0 으로 하여 OSRdyTble[] 이라는 배열의 맴버 변수들의 값을 채워 넣는다.


(4) 이렇게 해서 완성된 OSRdyGrp 라는 변수를 OSUnMapTlb[] 라는 LookUp Table 에 대입하여 값을 얻는다.


이 테이블은 0~255 의 숫자를 Binary 로 표시할때 제일 먼저 1이 나오는 bit 의 순서를 써 놓은 것이다.

(5) (4) 에서 나온 결과값을 OSRdyTlb[index] 의 index 값으로 사용하여 OSRdyTlb[index] 값을 얻어낸다.

(6) 다시 OSUnMabTlb[OSRdyTlb[index]] 로 다시 Look-Up Table 의 값을 얻어낸다.



(7) (4)에서 여러분이 얻어낸 값은 "몇번째 그룹에서 최고 우선순위를 갖는 Task 가 Ready 상태인가? " 이고
     (6)에서 여러분이 얻어낸 값은 "해당되는 그룹에서 몇번째 순서의 Task가 Ready 되어있는 상태중에 최고 우선순위인가?" 이다.


(8) 즉, Ready 상태에 있는 최고 우선순위를 최종적으로 알아내기 위해서는

( (4)번 결과 << 3 ) + (6)번 결과

이다. 여기서 좌로 3비트 쉬프트 시킨 이유를 그룹을 8개씩으로 끊어 놓았기 때문이다. (2의 3승)


이해가 되시나요??

한번 스윽 읽어보는것만으로는 잘 이해가 안되실 것입니다.
저도 직접 구현해보기 전에는 신기하기만 할 뿐이였으니까요 ㅋㅋ

포스팅전에 확실하게 이해하기 위해서 제가 방금 1시간을 투자해서 위의 알고리즘을 구현해보았습니다.


보이시나요? 잘 찾아내지요?

체크되어있는 것들이 Ready 상태입니다. ㅋ

하나도 체크가 안되어있으면 레디상태인 테스크가 없다라고 메시지가 뜹니다.

어떻게 아냐구요??

if (OSRdyGrp == 0) 겠지용?? ㅋㅋ

아래는 제가 C# 으로 간단하게 구현해 놓은 프로젝트 입니다.

참고하실분을 받아서 보시길 바랍니다.

Visual Studio 2010 SP1 으로 제작된 것이니, 프로젝트 안열리시는 분들은 그냥 .cs 파일에서 알고리즘만 간단하게 보시기 바랍니다.

따로 다중 클래스화 시키지 않았으니 무리없이 보실수 있을 것입니다.

그럼 바이바이

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

RTOS 가 갖을 수 있는 취약점이 또 하나 나오는군요.
이번 개념 굉장히 중요합니다.

일단 이 문장은 기억하세요~

"우선순위 전도"를 해결 할수 있는 해결책은 "우선순위 상속"이고,
"우선순위 상속"을 하기 위해서는 커널이 "동적 우선순위"를 구현 할 수 있어야 한다.


오케이??

자! 다시 각하와 국무총리, 필자와 화장실을 들고 와 봅시다.

각하와 필자가 갑자기 큰일이 마려워졌어요 ㅋ 화장실은 1칸밖에 없고 열쇠도 1개밖에 없습니다.
이 열쇠는 다른 이름으로 "세마포어" 라고 부르고, 이 열쇠관리는 화장실 관리인인 커널의 "스케쥴러" 가 합니다.

필자는 비록 우선순위가 가장 낮지만, 재빠르기때문에 각하와 국무총리님이 화장실을 가고 싶어하기 전에 관리자에게 "열쇠점 주세요" 해서 화장실에 가서 일을 보기 시작했습니당 ㅋㅋ

신나게 일을 보고 있는데 각하가 급하게 나타나서리 "나도 화장실이 급하다. 열쇠 점 줘" 이랬습니다 ㅋㅋ 그랬더니
관리자가 "열쇠 없는댑쇼?? 기둘리셔야 할듯 ㅋㅋ" 이러는 거에요 ㅋㅋ
아무리 각하라지만, 민주주의 사회에서 이미 일보고있는 저를 끌어낼수는 없는 노릇이지요 ㅋㅋㅋ
그래서 각하는 "흠.. 그럼 열쇠가 다시 나올때 까지 기다리도록 하지. 어쩔수 없으니까... " 이러면서 대기를 타기 시작합니다 ㅋㅋ

제가 빠르게 일을 보고 나온다면야 문제가 커지지는 않겠지요 ㅋㅋ 그래서 빠르게 일을 보려고 하고있는데 갑자기 국무총리님이 " 아 커널. 나 급하게 미팅이 잡혔어. 씨피유좀 부여해조 나 일좀 하게" 라는거에요 ㅋ

아나 얼척이 없어서 ㅋㅋ 커널은 국무총리님이 일을 보신다니까 씨피유 점유율을 저보다 우선순위가 높은 국무총리님에게 줘버리는거지요 ( 대통령이 우선순위가 가장 높지만, 화장실(공유자원) 이라는 자원을 요청하는데 쓰고 있어서 씨피유 점유율을 부득이 하게 못 주는것입니다. 국무 총리는 화장실을 요청한게 아니니까 씨피유 자원을 주는 것이지요)

국무총리님이 한창 일을 열심히 합니다. 쭈욱, 오랜기간 ㅋㅋㅋ 일을 다 마치고 커널에게 "나 일 다 끝났다" 이러니까 커널은 누구에게 이제 씨피유를 서비스 해줄까~~~ 하고 둘러봅니다. 각하와 제가 레디 상태인데 둘다 화장실을 요구하는데 키는 저한테 있었지요 ㅋㅋ 제가 반납을 한적이 없으니까 ㅋㅋ 그래서 저한테 씨피유을 부여해줘요 ㅋㅋ

저는 이제 신나게 일을 보고 난 후 " 다 썼어요 키 반납할께요 " 라고 말하죠 ㅋ 그제서야 관리자는 최고 우선순위였던 각하에게 " 각하 키가 왔습니다 이용하시지요~" 라면서 키를 주죠 ㅋ

자 여기서 생각해 볼까요??

각하는 1순위였는데 실질적인 우선순위는 어떻게 되어버렸습니까? 3순위였던 저보다도 낮아져 버렸죠??

이렇게 되는 현상을 "우선순위 전도 (Priority Inversion)" 이라고 부릅니다

공유자원의 한정성 때문에 어쩔 수 없이 최고 우선순위를 대기 태우는 일이 발생하더라고, 빨리 공유자원을 풀어서 최 우선순위 테스크에게 서비스를 해줘야 커널의 본질에 맞는데 이것은 뭐 2순위 3순위 애들까지 다 서비스 해주고나서야 맨 꼴지로 최 우선순위 테스크를 서비스 해주는 상황이 벌어져버리니 황당할 노릇이지요 ㅋ

위의 비유는 여러분의 이해를 돕기 위한것이고, Task 실행도를 살펴보지요~ 제가 햇던 이야기들이 고스란히 들어있습니다.


자 이해 되세여? ㅋㅋ 테스크 1이 꼴등으로 실행되어 버리네요 ㅋㅋㅋ

이런 문제를 해결하기위한 방법으로 어떤 것이 있을까요???

화장실을 이용하고 있던 저의 우선순위를 잠시동안 각하와 동급이나 그 이상으로 만들어 주는것입니다.

즉, 각하의 우선순위를 "상속" 해 주는것이지요 ㅋㅋ

그럼 , 제가 일보고 있을때 국무총리가 자기 일 있다고 CPU 서비스좀 해달라고 했을때 스케쥴러는 " 그럴수 없습니다 후달수 님아~~ " 이러면서 저는 꾸준히 화장실을 재빠르게 이용하겠죠 ㅋㅋ

다 이용한 후에 다시 제 우선순위를 원래의 양민 레벨로 돌려주고 나면 바로 최고 우선순위인 "각하" 께서 화장실을 이용하게 되시고~ 다 이용하신 후에 국무 총리 님이 업무를 보시게 되는것입니다 ㅋㅋ

이제 커널이 좀 제대로 돌아가는것 같지요?? ㅋ

요로코롬 돌아가게 됩니다 ㅋㅋㅋ

이제 맨처음에 꼭 기억하셔야 한다던 한문장이 이해가 되시지요?? ㅋㅋ

이렇게 공유자원을 이용할때 최고 우선순위를 일시적으로 부여 하는 행위를

우선순위 상속 (Priority Inheritance) 라고 부르고, 이 행동을 할 수 있으려면,

어플리케이션이 실행중일때 우선 순위를 바꿀 수 있는 동적 우선순위(Dynamic Priority) 를 커널이 구현할수 있어야 한답니다 ㅋㅋ

이해가 되셨기를 바랍니다

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

우선순위를 논해야 될때가 되었군요 ㅋㅋ

전 강의에서 비선점형 커널과 선점형 커널 이야기를 하면서 우선순위 우선순위 했는데 감이 오셨어요?
사실 뭐 별게 없습니다~

어떤 Task 가 더 중요한 Task 인가??? 인것이죠 ㅋㅋ

곰곰히 생각해보면 이놈의 커널은 참 민주사회의 부패를 그대로 뺴다 박아 놓은놈 인것 같습니다.

온국민은 평등해야 하는데 실상 우리 사는 사회가 그렇지가 않잖아요 ㅋㅋ

아니라구요????

화장실이 한칸있습니다.
화장실 주인이 화장실에 들어갈 사람을 결정 할 수가 있어요 ㅋ

근데 저랑 각하랑 같이 응가가 마려운거에요 ㅋㅋ 그래서 화장실 주인한테 동시에 저 응가가..... 마려... 워...요...

라고 말했습니다. ㅋㅋ 근데 이놈의 화장실 주인이라는 놈이 뒤 돌아 볼것도 없이 무조건 "각하" 에게 화장실을 쓰라고 한다는 것이지요 ㅋ
(아... 더러운 세상 ㅋㅋ 이러실 필요는 없어요 ㅋㅋ 각하보다 쫌만 더 빨리 요청하면 내가 쓸수 있으니까요 ㅋㅋ)

다음강의에서 계속될 Priority Inversion 과 세마포어를 이야기하면 지금과는 조금 상황을 이야기 할 수 있습니다 ㅋ

(흠.. 쓸것도 없는데 왜 이 글을 쓴다고 했을꼬 ㅋㅋㅋ)

Group Priority 라는 것이 있습니다 ㅋㅋㅋ

그룹단위로 일단 우선순위를 한번 나눠 놓은 후에 세부 우선순위를 나누려는 개념이지요 ㅋㅋㅋ

Group 1 : 공자 맹자 예수 장자 + 필자
Group 2 : 찌우, 다람쥐, 토끼, 멍멍이
Group 3 : 지렁이, 무뇌충

역시 그룹 1이 킹왕짱입니다 ㅋㅋ

이제 스케쥴러는 그룹의 우선순위를 먼저 따진 후에, 각 그룹 안의 맴버들 각각의 우선순위를 다시 따져 줍니다 ㅋ

즉 Group 2 에서 찌우가 킹왕짱이더라고 Group 1의 핫빠리인 장자 보다 못하다는 소리이지요 ㅋㅋㅋ

사실 커널에 따라서 Group Priority 를 지원하지 않는 것도 있습니다 ㅋ

하지만 제가 사용하는 커널은 RTX Kernel 은 이를 지원하는군요 ㅋㅋ

Priority 의 숫자가 큰것이 우선순위가 높은 것일 수도 있고, 작은것이 높은것일수도 있습니다 ㅋ

즉, 커널 디팬던트 하다는 소리이지요 ㅋㅋ

메뉴얼을 꼭 살펴 보셔야 한다는 소리입니다 ㅋ

우선순위의 종류에는

(1) Static Priorities (정적 우선순위)
(2) Dynamic Priorities (동적 우선순위)

이렇게 크게 두가지로 나눈수 있는데요 ㅋ 머 딱히 설명 드리지 않아도 이제 감이 오지 않습니까? ㅋㅋㅋ

테스크의 우선 순위를 바꿀수 없다면 정적 우선순위요, 어플리케이션이 실행되는 동안에 태스크의 우선순위를 바꿀 수 있다면 이럿은 Dynamic 한 우선순위가 되는것이지요 ㅋㅋ

쉬운 개념이니 쉬어가는 코너로 생각하시고 넘어가시길 바랍니다 ㅋ

다음에 설명할

Priority Inversion 과 Priority Inheritance 가 중요한 개념이니까요 ㅋㅋㅋ  (우선순위 전도와 우선순위 상속) ㅋ

여려분에게 우선순위는 어떻게 되시나요??? ㅋㅋㅋ

아래는 제가 가지고 싶어하는 CPU 3960X ㅋㅋㅋ

저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by J.Bear
이제 슬슬 RTOS 의 핵심으로 들어가고 있습니다.

시작하기 전에 사진 한 컷! 이것은 현재 저의 입천장 사진입니다.

사실 요전 4일동은 39도가 넘는 고열에 시달리며 새해를 맞이했지용.

응급실에서 주사를 맞으면서 ㅋㅋ

태어나서 이렇게 짧은기간에 이렇게 많은 병원과 주사를 맞아본 기억이 없습니다.

그때 고열로 시달리다가 입천장이 다 헐어 버려서 지금 음식도 못먹고 허미.....

 

보이시나요. 헐어서 살이 다 벗겨지고 노랗게 염증도 생기고 ... ㅠㅠ
정말 이렇게 공부해서 어디다 쓰나, 무슨 부귀영화를 누리자고 이러나 싶기도 하지만 ㅋㅋ
일단 스케쥴러와 커널의 종류에 대해서는 공부해놓고 마저 생각합시다.

그럼 시! 작!

1. 스케쥴러

이름부터가 딱 직관적입니다. 스케쥴을 짜주는 놈이지요. 디스패처(Dispatcher) 라고도 하는데요, 이놈이
다음번에 실행할 테스크를 결정한답니다.
Context Switching 이 일어나기 위한 조건은 Interrupt Service Routine 이에요 ㅋ

왜 그러냐규요??

ISR 에 의해서 테스크는 자신의 CPU 점유권을 놓게 되지요~ 그것이 Tick ISR 이던, Timer ISR 이던 DMA ISR 이던 상관없이 말이에요~

그 이후에 CPU 점유율은 커널의 스케쥴러가 갖습니다.
어떤 형태의 커널인지에 따라 이 스케쥴러는 레디 상태에 있는 테스크 들로부터 다음에 서비스를 해줘야 할 테스크를 결정하게 됩니다. 대부분의 커널들은 우선순위가 높은 테스크에게 점유율을 넘기지용~ ㅋㅋ

스케쥴러~ 내 프로그램의 스마트한 교통 순경 정도로 생각해 두시면 좋을듯~~

2. 커널의 종류 : 비선점형 커널, 선점형 커널 로 나눌 수 있다.

(1) Non-preemptive Kernel (비 선점형 커널) 

 선점을 하지 않는 커널. 먼저 점령을 하지 않는 커널.

풀어쓰니 위와 같이 되는군요?? ㅋㅋ 먼저 점령을 하지 않는다. 뭐를? CPU 점유권을~

쉬운 개념인데 이름을 좀 아리까리 하게 지은것 같기도 해요 ㅋㅋㅋ

이전 포스트에서 커널의 종류를 나누는 기준은 ISR 후에 어떤 Task 로 CPU 점유권을 넘길것이냐에 대한
원칙이 무엇이냐에 따라 종류가 결정된다고 했었던 것 기억나시나요?

비 선점형 커널은, 무조건 ISR 로 뛰어들어가기전에 돌고 있던 Task 로 다시 CPU 점유권을 넘기는 커널입니다.
아무리 우선순위가 명박이 할애비 보다 높다고 해도 필요없어요 ㅋ 꿋꿋하게 원래 돌던 놈에게 다시 넘겨주조 ~ ㅋ

그럼 이 커널은 멀티태스킹을 언제하느냐???
태스크에서 자체적으로 자신의 CPU 점유권을 놓아야 합니다 ~ OS_Dly_wait(10) 같은 방식으로요 ~ ㅋㅋㅋ

 


그림으로 보니 한결 더 이해가 빠르지요?? ㅋㅋ

그럼 어떤 특징이 있을까용?

1. 인터럽트 지연시간이 짧습니다. (흠.. 개인적으로 저는 인터럽스 지연시간은 잘 모르겠고, 인터럽스 응답시간과 복귀시간이 짧다고 말하고 싶은데 빌딩블록에는 이렇게 써있네요 ... ㅠㅜ)
2. 테스크 레벨에서도 비재진입 함수를 사용할수 있습니다 (테스크 자신이 제어권을 넘겨주기 전에는 절대로 다른 테스크로 제어권이 넘어가지 않기 떄문에, 일 다하고 제어권을 넘기면 됨ㅋㅋ)
3. 테스크의 응답성이 떨어진다. (재수업게 졸라 수행시간이 긴 테스크가 돌고있다고 가정해보세요 ㅋㅋ 우선순위가 졸라 높은 테스크가 대기중인데 제어권이 넘어올 생각을 안한다면?? 후덜덜 ㅋㅋㅋ) 

초창기 리룩스 커널과 Window3.1 이 비선점형 커널이였습니다 ㅋ
그래서 한번 뻑나면 컴퓨터 전원을 끄는 것 밖에 방법이 없었지요 ~ ㅋㅋ

도대체 CPU 점유율을 뻇어올 방법이 없거등요 ㅋㅋㅋ 훗날 다 선점형 커널로 바뀌었지만 말이죠 ㅋ

하지만 반대로 프로그램을 정말 잘 짜놓았다면?? 굉장히 안정적으로 돌릴수 있는 커널은 비 선점형이 되겠지요 ㅋㅋ 

(2) Preemptive Kernel

선점형 커널 ㅋㅋ 

이제 감이 오시죠? ㅋㅋ

딱 반대입니다. ISR 로 부터 복귀할 때 스케쥴러는 최 우선순위를 갖는 테스크에게 씨피유 점유율을 넘깁니다 ㅋ

좀더 복잡한 로직으로 동작하지만 프로그램의 응답성이 굉장히 개선이 되겠지요?

최고 중요한놈부터 꾸준히 서비스를 할수 있어 지니까요 ㅋㅋ

선점형 커널에서는 최상위 우선순위 태스크가 언제 CPU 의 서비스를 받을수 있을지 알수 있습니다.

하지만, 그렇다 보니까 Critical Section , 비재진입 함수의 사용 등에서 문제점이 발생하지요 ㅋ

아직 일이 덜 끝난상태에서 나보다 중요한 놈에게 CPU 서비스가 넘어갔는데 같은 비재진입 함수를 콜해버리고이러면 데이터가 완전히 꼬여버리자나요 ㅋㅋ

그래서 상호 배제적으로 공유자원에 접근을 하기 위한 노력들이 일어납니다 ㅋ

총 4가지의 방법이 있는데요~ 그것은 다음에 다루도록 하구요 ㅋ 지금은 제목만 알려드릴게요

1. 인터럽트 Enable/Disable
2. Semaphore 의 사용
3. TAS (Test and Set)
4. Scheduler Lock/Unlock

의 방법을 이용해서 공유자원에 상호 배제적으로 접근할 수 있답니다 ㅋㅋ

아 이번 강의 너무 길어지네.

너도 다시 공부하고 정리하는거라서 시험공부도 되고 좋네요 ㅋ
이거 그대로 인쇄해서 읽어보면서 셤공부해야겠네 ㅋ
하다가 빼먹은거 있으면 나중에 보충설명 해 드릴게요 

일단 선점형 커널의 이벤트 그림 올려드립니당

 

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