Linux · POSIX mqueue · API semantics

POSIX 메시지 큐: 이름·메시지·수명을 구분합니다

큐를 열었다고 해서 새 큐를 만든 것은 아닙니다. 생성 속성, 우선순위, 수신 버퍼, 대기와 이름 제거를 따로 확인해야 합니다.

생성 속성은 기존 큐를 재설정하지 않습니다

mq_open의 O_CREAT는 큐가 없을 때 생성합니다. 기존 큐를 열면 mode와 생성용 attr로 권한·용량이 다시 설정되지 않습니다. 새 큐만 허용하려면 O_CREAT와 O_EXCL을 함께 사용하고 EEXIST를 처리합니다. 새 큐의 권한에는 umask가 적용됩니다.

열기에 성공한 뒤 mq_getattr로 mq_maxmsg, mq_msgsize, mq_curmsgs를 읽습니다. 수신자는 자신이 요청했던 크기가 아니라 실제 열린 큐의 mq_msgsize에 맞춰 버퍼를 준비해야 합니다. 이름은 같아도 이전 실행이 남긴 큐일 수 있습니다.

mq_open(3) · mq_getattr(3)

메시지 경계와 우선순위를 보존합니다

mq_receive는 가장 높은 우선순위의 메시지 중 가장 오래된 것을 꺼냅니다. 모든 메시지가 단순 FIFO로 섞이는 것이 아니라 같은 우선순위 안에서 순서가 유지됩니다. 높은 우선순위만 계속 들어오는 상황은 낮은 우선순위 작업의 지연을 만들 수 있으므로, 우선순위 정책과 부하를 함께 설계합니다.

수신 버퍼는 다음 메시지의 실제 길이만큼이 아니라 큐의 최대 메시지 크기인 mq_msgsize 이상이어야 합니다. 작으면 EMSGSIZE입니다. 반환된 바이트 수로 데이터를 해석하며, 임의의 메시지가 NUL로 끝나는 문자열이라고 가정하지 않습니다.

mq_receive(3) · mq_send(3)

가득 찬 큐와 빈 큐의 대기를 구분합니다

기본 blocking 동작에서 송신은 큐가 가득 차면, 수신은 큐가 비면 기다립니다. O_NONBLOCK이면 각각 EAGAIN으로 돌아옵니다. 재시도 여부와 버리기·재전송·종료 정책은 애플리케이션에서 정해야 합니다.

mq_timedsend와 mq_timedreceive는 CLOCK_REALTIME 기준의 절대 시각을 받습니다. 상대 대기시간을 그대로 넣지 않습니다. EINTR 후 재시도할 때 기한을 매번 새로 늘리지 않도록 하고, ETIMEDOUT을 실제로 처리합니다. 시스템 시각의 변경도 절대 기한에 영향을 줄 수 있습니다.

mq_timedsend(3) · mq_timedreceive(3)

닫기와 이름 제거는 다른 일입니다

mq_close는 현재 descriptor를 닫습니다. mq_unlink는 이름을 즉시 제거하지만 이미 열린 descriptor가 있으면 큐 객체는 마지막 descriptor가 닫힐 때까지 남습니다. 종료할 때 어느 프로세스가 이름을 제거할지 합의하지 않으면, 재시작할 때 오래된 큐를 다시 열 수 있습니다.

이름과 열린 참조의 수명
  1. mq_open: 이름으로 큐 참조 획득

  2. mq_unlink: 이후의 이름 검색에서 제거

  3. 마지막 mq_close: 남아 있던 큐 객체 소멸

mq_unlink(3) · mq_close(3)

Linux의 관측값을 정확히 읽습니다

/dev/mqueue는 mqueue 파일시스템이 그 위치에 마운트된 경우의 관측 경로입니다. 컨테이너에서는 IPC namespace도 확인합니다. QSIZE는 메시지 데이터의 바이트 수이며 mq_curmsgs처럼 메시지 개수가 아닙니다. NOTIFY는 알림 방식 번호이지 단순한 켜짐·꺼짐 값이 아닙니다.

생성 실패에서는 /proc/sys/fs/mqueue의 큐 수·크기 제한과 실제 UID에 적용되는 RLIMIT_MSGQUEUE를 함께 확인합니다. 이 글은 API와 문서의 정적 대조이며 Linux에서 예시를 빌드하거나 실행한 결과가 아닙니다.

mq_overview(7)