📻 minitalk
시그널 핸들러는 비동기 작업을 지원하기 때문에 데이터 레이스가 자주 발생하며, 다양한 원인과 증상이 존재한다.
리눅스 시스템은 같은 유형의 시그널이 이미 보류 중일 경우 시그널을 대기열에 넣지 않는다.
보류 시그널은 일종의 플래그 처럼 동작하며 SIGUSR1
이 연속 3번 전달되었다고 가정할 때의 슈도 코드는 다음과 같다.
시그널을 처리한다.
시그널을 처리 중이므로 대기열에 SIGUSR1
을 넣는다.
pending[SIGUSR1] = 1;
시그널을 처리 중이므로 대기열에 SIGUSR1
을 넣는다. (누락 발생!)
pending[SIGUSR1] = 1; // 덮어씌워지므로 누락 발생
(1)에서의 시그널 처리가 끝나 보류 중인 시그널을 가져온다.
pending[SIGUSR1] = 0;
즉, 시그널 핸들러의 수행 시간이 길어질수록 누락되는 시그널이 많아지게 된다.
가장 좋은 해결책은 시그널은 단 한 번만 호출되도록 설계하고 단순 플래그 설정으로 끝내는 것이다.
void handler(int sig) { flag = sig; }
하지만 minitalk에서는 연속적으로 시그널을 받아야하므로 여러 방법으로 우회를 해야한다.
<aside> ⚠️ 100 글자를 전송하는데 1초가 소요되면 굉장히 느린 겁니다
처리 방법
server는 별도의 sleep 없이 시그널을 대기한다.
client는 적절한 sleep을 통해 시그널 전송 속도를 적절히 조절한다.
[방안2] 최대한 핸들러를 짧게 작성하고 서버에서 응답 시그널을 통해 재전송을 요청한다.
<aside> 💡 직렬 통신 관련 표준 규격인 RS485에서는 충돌 감지를 위한 모드가 존재한다.
모드 | 설명 |
---|---|
Echo Mode | - 성공 시, 전송 데이터를 그대로 루프백한다. |
Echo Mode의 개념을 적용한 시그널 처리 방식은 다음과 같다.