강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

jinh2352님의 프로필 이미지
jinh2352

작성한 질문수

FreeRTOS 프로그래밍

소스코드 분석-printf 와 fflush

'소스코드 분석-printf와 fflush' 부분 질문이 있습니다!

작성

·

458

1

"fflush 함수는 버퍼를 비우고, 이에 따라 출력장치의 동작을 야기시킵니다. 그런데 UART 장치의 동작은 매우 느리기에 예상치 못한 출력 결과를 야기시킵니다."

위와 같이 수업에서 이해를 하였습니다!

그런데 'a'를 출력하는 Task1도 'b'를 출력하는 Task2도 둘다 fflush 함수가 동작을 하는데 왜 a a a a .. a a b a a a.. 와 같이 비대칭적인 결과가 나오는 걸까요? 

둘다 fflush 함수가 있기에 출력이 느려지더래도 대칭성은 유지될 것으로 예상하였었습니다. 

답변 1

0

홍영기님의 프로필 이미지
홍영기
지식공유자

jinh2352님!

혹시 질문하신 내용이 영상 몇분 몇초 구간인지 알 수 있을까요? 3분 정도의 영상을 들여다 보았는데, 그런 상황이 없는 것 같아서 질문드립니다.

FreeRTOS 프로그래밍소스코드 분석-printf 와 fflush

vTaskDelay 가 사용되었다면 위와 같은 결과가 나올 수 있습니다.

 

jinh2352님의 프로필 이미지
jinh2352
질문자

근래 바빠서 잠시 공부를 놓았다 다시 보게 되어 답변이 늦었습니다 ㅠ

 

(비대칭적 출력 1분 10초대)

https://www.inflearn.com/course/freertos-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/lecture/82500?tab=curriculum

(비대칭적 출력에 대한 해설, fflush 동작으로 인한)

FreeRTOS 프로그래밍소스코드 분석-printf 와 fflush

 

위 회차 수업에서 동일한 우선순위를 가지는 Task1, Task2가 작동함에도 불구하고 a a a a .. a a a b a a a a... a a a b 와 같이 비대칭적으로 출력되는 부분이 fflush 함수의 작동으로 느린 UART 장치가 작동되기에 그런 것이다 라 설명해주셨고, 

Task1, Task2 에서 모두 fflush를 주석처리하면 대칭적인 출력이 나옵니다.

 

이 점이 그냥 궁금했던 것입니다! 동일한 우선순위 Task1, Task2 둘다 fflush 함수를 호출하는데 비대칭적인 출력이 발생하는 것이 이해가 잘 되지 않습니다. 똑같이 작동이 느려지기에 결국 대칭적인 출력이 나와야한다 생각되기 때문입니다! 

홍영기님의 프로필 이미지
홍영기
지식공유자

jinh2352님! 반갑습니다:)

두 개의 태스크가 같은 우선순위를 사용하며, fflush 을 사용하는 경우를 말씀하시는 것이군요.

기본적으로 화면에 출력되는 내용만 그렇게 보이는 것일뿐 실제적으로는 jinh2352님 표현대로 대칭적인 모습으로 실행(라운드로빈)되고 있을 것입니다.

다양한 방법으로 그 것을 확인하실 수 있을터인데, 그 중 간단한 방법 하나를 알려드릴게요.

각각의 태스크를 이런식으로 코드 수정후 실행해보시죠.

#if 1 // No comment

//vTaskDelay (pdMS_TO_TICKS (1000));

i++;

if((i%100)==0){

printf("b"); fflush(stdout); // 문자 'b' 출력

}

#endif // TODO #3

 

 

실행 결과는 다음과 같은 것일텐데요.

bbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbbaaaaaaaaaaabbbbbbbbbbba

 

그럼 과거에 실행 결과가 a a a a .. a a a b a a a a... a a a b  

이런 식으로 나왔던 이유는 fflush 나 printf 함수 자체가 재진입(reentrant) 함수가 아니라는 점과 __io_putchar 함수내에서 사용하는 HAL_UART_Transmit 함수의 구현 방법 때문으로 보실 수 있어요. 

int __io_putchar(int ch)

{

if ( ch == '\n' )

HAL_UART_Transmit(&huart2, (uint8_t*)&"\r", 1, HAL_MAX_DELAY);

HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY);

 return ch;

}

 

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

{

  uint8_t  *pdata8bits;

  uint16_t *pdata16bits;

  uint32_t tickstart = 0U;

 

  /* Check that a Tx process is not already ongoing */

  if (huart->gState == HAL_UART_STATE_READY)

  {

    if ((pData == NULL) || (Size == 0U))

    {

      return  HAL_ERROR;

    }

... 중략

 

 

printf 사용하시면서 이러한 출력이 나온걸 보신적 있을 수 있습니다.

Hello, Wo다른문자열rld 

 

이것은 printf가 재진입 함수가 아니라는 것을 잘 보여줍니다

 

이것만 기억하시면 될 것 같아요.

fflush 함수를 이용할 때는 출력 결과를 맹신하지 말자.

이 함수는 꼭 필요한 경우외엔 가급적이면 사용하지 않는 것이 좋다.

 

궁극적인 해결 방법은 printf, fflush 을 재진입 함수로 만드는 것일텐데요.

재진입 함수로 만드는 것은 상호배제를 통해 실제 가능은 합니다. 하지만 상호배제에는 비용(오버헤드)이 발생하기 때문에 즐겨 사용되지 않습니다. 또한 이 함수가 상호배제를 내장하고 있는 경우 함수 내부에서도 문맥 전환이 발생하게 됨으로써 테스트 환경을 왜곡시킬 위험 또한 있습니다.

jinh2352님의 프로필 이미지
jinh2352

작성한 질문수

질문하기