반응형

 

 

공유자원인 시리얼을 두 개의 태스크가 동시에 기록하면 아래처럼 첫번째 태스크에서 다 기록하기 전에 두번째 태스크가 선점하여 문자열을 출력하는 원치 않은 결과를 얻을 수 있다.

 

이를 방지하기 위해서 뮤텍스 타입의 세마포어를 사용하여 시리얼을 사용 중일 때에는 다른 태스크가 시리얼에 접근 할 수 없도록 막는다.

정상적으로 수행되는 경우의 결과…

 

  1. /* FreeRTOS.org includes. */  
  2. #include "FreeRTOS_AVR.h"  
  3. //#include "task.h"  
  4. //#include "semphr.h"  
  5.     
  6. /* Compiler includes. */  
  7. //#include <stdlib.h>  
  8. //#include <stdio.h>  
  9.     
  10. //화면에 문자열을 출력하는 태스크를 위한 함수  
  11. static void prvPrintTask( void *pvParameters );  
  12.     
  13. //뮤텍스 타입 세마포어를 이용하여 공유자원인 시리얼을 동시에 사용하지 못하도록한 새로운  
  14. //문자열 출력함수  
  15. static void prvNewPrintString( const char *pcString );  
  16.     
  17. /*-----------------------------------------------------------*/  
  18.     
  19.     
  20. //SemaphoreHandle_t 타입의 변수를 여기에서는 뮤텍스 타입의 세마포어를 위해 사용된다.  
  21. //공유자원인 시리얼로의 출력을 동시에 사용하지 않기 위해서 사용됨(상호배제  mutual exclusive)  
  22. //예를 들어 첫번째 문자열 출력도중에 두번째 문자열을 출력하게 되는 상황이 안벌어지게 한다.  
  23. SemaphoreHandle_t xMutex;  
  24.     
  25.     
  26. void setup( void )  
  27. {  
  28.   Serial.begin(9600);  
  29.       
  30.   //뮤텍스 타입의 세마포어를 생성한다.  
  31.   xMutex = xSemaphoreCreateMutex();  
  32.     
  33.       
  34.   //난수를 발생시키기 위한 시드값  
  35.   //태스크가 랜덤한 시간동안 블록되게 만들때 사용할 rand함수를 사용 하위한 작업  
  36.   srand( 567 );  
  37.     
  38.   if( xMutex != NULL ) //뮤텍스타입의 세마포어가 정상적으로 생성되었다면  
  39.   {  
  40.     
  41.     // 개의 문자열을 출력하는 태스크를 생성한다.  
  42.     //우선순위를 다르게 했기 때문에 하나의 태스크를 수행중 다른 태스크가 실행될수 있게 했다.  
  43.     xTaskCreate( prvPrintTask, "Print1", 200, (void*)"Task 1 ******************************************\r\n", 1, NULL );  
  44.     xTaskCreate( prvPrintTask, "Print2", 200, (void*)"Task 2 ------------------------------------------\r\n", 2, NULL );  
  45.     
  46.     //스케줄러를 시작한다.  
  47.     vTaskStartScheduler();  
  48.   }  
  49.     
  50.   //여기에 도달하면 아마도 메모리 부족  
  51.       
  52.   for( ;; );  
  53. //  return 0;  
  54. }  
  55. /*-----------------------------------------------------------*/  
  56.     
  57. static void prvNewPrintString( const char *pcString )  
  58. {  
  59.   //뮤텍스 타입 세마포어를 무한 시간동안 기다리게 된다.  
  60.   //얻지 못하면 블록상태가 되버림.얻을때에만 블록이 풀리기 떄문에 리턴값을 체크할 필요가 없음.  
  61.   xSemaphoreTake( xMutex, portMAX_DELAY );  
  62.   {  
  63.     /* The following line will only execute once the semaphore has been 
  64.     successfully obtained - so standard out can be accessed freely. */  
  65.     //printf( "%s", pcString );  
  66.     //fflush( stdout );  
  67.     
  68.       Serial.print(pcString);  
  69.       Serial.flush(); //시리얼 포트에 있는 데이터가  기록될때 까지 대기한다.(아두이노 1.0 이전 버전에선 삭제했음)  
  70.     
  71.   }  
  72.   xSemaphoreGive( xMutex );  
  73.     
  74.     
  75.   if( Serial.available() ) //버퍼가 비어있지 않다면 True 반환한다.  
  76.   {  
  77.     //커널 틱을 정지시키고 모든 생성된 태스크들을 삭제한다  
  78.     //시리얼 포트에 있는 데이터가  기록될때 까지 위에서 기다렸는데도 버퍼가 꽉차있다는 것은   
  79.     //먼가 문제가 있는 것이므로 스케줄러를 다시 시작하는 것으로 보인다.  
  80.     vTaskEndScheduler();  
  81.   }  
  82. }  
  83. /*-----------------------------------------------------------*/  
  84.     
  85. static void prvPrintTask( void *pvParameters )  
  86. {  
  87.   //파라메터로 받은 문자열을   
  88.   char *pcStringToPrint;  
  89.   pcStringToPrint = ( char * ) pvParameters;  
  90.     
  91.   for( ;; )  
  92.   {  
  93.     //시리얼로 문자열을 출력하기 위해 새로 만든 함수를 이용한다.  
  94.     prvNewPrintString( pcStringToPrint );  
  95.     
  96.     //rand 생성한 임의의 시간동안 대기한다.  
  97.     //여기에서 critical section없이 사용하려면 rand함수가 reentrant해야 한다  
  98.     //여러 쓰레드에서 코드를 동시에 수행하더라도 실행결과가 정확함을 보장한다는 것이다.  
  99.     vTaskDelay( ( rand() & 0x1FF ) );  
  100.   }  
  101. }  
  102. //------------------------------------------------------------------------------  
  103. void loop() {}  


문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts