fflush질문
302
작성한 질문수 3
강사님 안녕하세요
틱 인터럽트 기준 1ms동안 버퍼에 문자1000개가 들어가는 속도라 하고 버퍼는 100개까지 채울수 있다는 가정시
fflush함수가 없을 때는
a 100개가 1*10번 / b 100개가 1*10번
번갈아 출력되는거죠?
그런데, fflush함수가 있으면
a 1개가 100*10번나오지 못하다 끝나고
b 1개가 100*10번나오지 못하다 끝나야 하는데
말씀하신 uart로직이 결부되었으나
aaaaaabaaaaaabaaaaaab 이런 패턴은
b 태스크에만 영향을 받는것 처럼 보이는데
제가 질문한 예시로 답변 가능할까요??..
답변 1
1
답변을 여기 올려드렸어요 <-- 클릭!
감사합니다.^^
0
수업처럼 딜레이 부분은 주석처리 한 상태에서 그 결과를 물어봤는데
저의 전달이 미약한것 같습니다~
수업내용처럼 vTaskDelay 없이
fflush유무 에 따른 결과가 이상해서 질문 드렸습니다~
딜레이가 없으니 tick인터럽트 주기만큼(1ms전제) tast1 실행, task2실행 이것을 반복하잖아요~

이것은 aaabbbaaabbb 동일하게 나오는데
fflush를 두 task에 추가하면 aaaaaabaaaaaab 나오는 현상이요~
말씀하신 uart로직이 결부되었으나
uart로 인한 하드웨어 지연현상은 tast1 , task2 둘다에 나타나니 결과적으로 패턴은 규칙적이어야 하는데 어느 한 태스크에만 영향을 받는것 처럼 보이는 문제요!
2
일꾼1과 일꾼2가 있습니다.
두사람은 목재를 옮기는 일을 하고 있습니다.
주인장이 와서 시장에 가서 여기 메모지에 적혀있는 물건을 사오라고, 일꾼2에게 말합니다.
일꾼2는 심부름때문에 그날 끝냈어야 할 일을 다하지 못했습니다.
태스크1(화면에 a 을 출력하고 있다) . . .일꾼1에 비유... a 는 목재를 옮기는 일
태스크2(화면에 b 을 출력하고 있다). . .일꾼2에 비유... b 는 목재를 옮기는 일
아래 그림을 보시죠. T1 과 T2 는 라운드로빈으로 시간을 공평하게 나눔받아 실행중입니다.

그런데, T1 은 압도적으로 T2보다 더 많이 작업을 실행한 것처럼 보입니다. 왜 그럴까요?
아까의 비유를 보죠. 일꾼1이 오늘 한 일은 (1)목재를 옮기는 일이 전부입니다
하지만, 일꾼2가 오늘 한 일은 이 두가지입니다 (1)목재를 옮기는 일, (2)심부름
목재를 옮기는 일을 일꾼의 주된 일(work) 로 본다면, 심부름은 사이드 일로 볼 수 있어요.
하지만 심부름도 일이 아닌것은 아니죠.
b 을 화면에 찍고 있는 T2 는 T1 이 하지 않는 허드렛일을 조용히 안보이는데서 처리하고 있는 것입니다. 바로 UART 장치( HAL_UART_Transmit )를 이용해서 화면에 실질적인 출력을 하도록 하는 일인 것이죠.

하지만, 일꾼2는 다음에 비슷한 일이 있을 때 자리를 피합니다. 결국 심부름은 일꾼1이 하게됩니다.
다음의 코드를 보세요. vTaskDelay(1); 기존의 코드에 함수를 한 줄 끼워 넣습니다.
vTaskDelay(1); // ⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️ 이부분을 잘 보세요.
while(1) {
/* TODO #3:
코드를 실행 하여 보고
vTaskDelay() 코드를 주석 처리한 후 그 결과를 설명한다 */
#if 1 // No comment
//vTaskDelay (pdMS_TO_TICKS (1000));
printf("a"); fflush(stdout); // 문자 'a' 출력
#endif // TODO #3
그러면 다음과 같은 현상으로 나타납니다.

왜 이런 현상이 나타날까요.
vTaskDelay(1)을 T1 코드에 끼워 넣었기 때문에
T2가 T1 보다 while 루프를 먼저 실행하게되죠. 1밀리초 동안 버퍼에 'b' 문자들이 채워지기 시작합니다. 그리고, 운이 나쁘면 T2 는 계속 UART 장치에 글자를 출력하는 일만 도맡아하게 될 수 있습니다. 이것이 위 출력 결과의 해석입니다.
자, 이제 결론으로 가보죠
제가 강의에서도 충분히 지적하였지만, printf 사용하실 땐 주의하셔야 합니다. 화면에 나오는 출력이 실시간이라고 믿으시면 안되는 이유가 여기 있습니다.
아래 함수에서 __HAL_LOCK(), __HAL_UNLOCK() 을 보시면 됩니다.
일종의 임계구역이 형성되어 있습니다. T1이 임계구역으로 들어가서 실행하는 동안 선점되어 T2가 동일한 임계구역으로 들어갈 수 없도록 설계되어 있는 것이죠. 결국, 운이 나쁘면 어떤 태스크는 죽어라 이 작업을 다른 태스크에 비해 과도하게 해야 할 수 있습니다. 그렇다면 printf 을 사용하지 않고 uart_printf() 을 이용하는 방법도 고려해 볼 수 있겠지만, 서로 일장 일단이 있어서 이 방법이 저 방법보다 확실히 우월하다고 단정지을수는 없습니다.
printf 라는 것이 본시 주 용도가 디버깅이기 때문에 기기의 디버깅시 실시간으로 동작하는 것을 항시 병행해서 테스트해야 합니다. 다시말하면 printf 을 온오프시켜가면서 테스트해야 한다는 것이죠. 개발자가 그만큼 주의를 기울여야 한다는 뜻이기도 합니다.
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;
}
/* Process Locked */
__HAL_LOCK(huart); // ⭐️⭐️⭐️⭐️⭐️
huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX;
/* Init tickstart for timeout managment */
tickstart = HAL_GetTick();
huart->TxXferSize = Size;
huart->TxXferCount = Size;
/* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
{
pdata8bits = NULL;
pdata16bits = (uint16_t *) pData;
}
else
{
pdata8bits = pData;
pdata16bits = NULL;
}
/* Process Unlocked */
__HAL_UNLOCK(huart); // ⭐️⭐️⭐️⭐️⭐️
while (huart->TxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
pdata16bits++;
}
else
{
huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
pdata8bits++;
}
huart->TxXferCount--;
}
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
/* At end of Tx process, restore huart->gState to Ready */
huart->gState = HAL_UART_STATE_READY;
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
0
강사님 그렇다면 aaaaaaaaaaaab인상황에서
task2가 uart를 출력하는 것만을 lock시키고 있고 task1는 uart가 lock때문에 실행이 안돼서 a만 누적시키는 상황이라고 보면될까요?
그러면 uart보내는 와중에도 switching이 일어난다는건가요??,,,,?
만약에 포팅을 할때 1년에 한번 잡는 치명적인 문제를 해결하는 코드가 들어갔다고 가정하면
0
57
2
STM32 포팅할 때 STM32 Project가 없음
0
166
2
FreeRTOS 멀티코어 지원안됨?
0
87
2
[소스코드 분석-configUSE_TIME_SLICING] TASK1,2의 우선순위가 동일할 때, configUSE_TIME_SLICING값 변경에 따른 출력 변화
0
83
2
포팅 부탁드립니다!
0
60
1
포팅 부탁드립니다. <NUCLEO-G071RB>
0
67
2
상호배제 후 되지를 않아서 질문드립니다.
0
61
1
수료증 발급 기준 수정 요청
1
72
1
재진입가능여부에 관한 질문
1
66
1
01_TASKMAN프로젝트 디버깅 모드 실패
1
77
2
그러면 malloc/free가 아닌 동적할당자를 써서 메모리를 할당했기떄문에
1
70
2
실행순서
1
76
2
uart 전송중에는 스위칭이 금지되나요?
1
74
2
스택오버플로우 실습 중 stack size 설정 질문
0
81
2
포팅 원합니다.
2
77
2
코루틴 실습질문
1
100
2
TODO 2번 문제
1
141
4
10. 선점형 커널 그림 설명중 우선순위가 반대인 경우에도 Task B가 먼저 수행되나요?
1
82
2
디버거모드에 진입이 안됩니다.
0
176
2
prvExampleTaskHook 함수 호출 부분에 대해 문의드립니다.
0
119
2
보드 STM32H735IG와 강의 호환 여부 문의
1
153
3
[ L152RE ] 원샷 소프트타이머 실행 잘 되시나요?
1
159
2
Deferred Interrupt Processing 샘플 예제 문의 드립니다.
1
121
2
포팅 서비스 부탁드립니다
1
125
2





