세마포어와 뮤텍스: 공유 자원 지키기
두 태스크가 같은 UART나 변수를 동시에 건드리면 데이터가 섞입니다. 뮤텍스로 잠그고, 세마포어로 신호를 줍니다.
문제
태스크 A가 UART로 "TEMP=25"를 보내는 도중 태스크 B가 끼어들어 "SPD=100"을 보내면 "TEMSPD=100P=25"가 나갑니다. 공유 자원은 한 번에 하나만 쓰게 해야 합니다.
뮤텍스: 열쇠 하나
xSemaphoreTake(uart_mutex, portMAX_DELAY);
uart_send(buf, len);
xSemaphoreGive(uart_mutex);
- 가진 태스크만 돌려줄 수 있습니다.
- 우선순위 상속이 들어 있어 우선순위 역전을 줄입니다.
- 인터럽트에서는 쓰지 않습니다.
세마포어: 신호
- 이진 세마포어: "일이 생겼다"는 신호. 인터럽트가 Give, 태스크가 Take하며 기다림
- 카운팅 세마포어: 자원이 N개일 때(버퍼 슬롯 N개) 남은 개수 관리
void USART1_IRQHandler(void) { // 인터럽트
BaseType_t woken = pdFALSE;
xSemaphoreGiveFromISR(rx_sem, &woken);
portYIELD_FROM_ISR(woken);
}
인터럽트에서는 반드시 FromISR 버전 함수를 씁니다.
데드락
A가 자원1을 잡고 자원2를 기다리고, B가 자원2를 잡고 자원1을 기다리면 둘 다 영원히 멈춥니다. 여러 자원을 잡을 때는 항상 같은 순서로 잡고, 잡고 있는 시간을 짧게 합니다. 아예 자원을 하나의 태스크가 소유하고 다른 태스크는 큐로 요청하게 만드는 것이 더 안전한 설계입니다.