Master the fundamental concepts of inter-process communication through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksMessage queues carry typed records with priorities instead of byte streams. SysV msgsnd/msgrcv and POSIX mq_open variants exist; both kernel modules maintain waiting receivers per queue.
Typical record:
For example, worker pool messages with mtype=1 for jobs and mtype=2 for control shutdown broadcast to all readers.
System V message queues predate and directly inspired the message-type-and-priority model that production brokers like RabbitMQ and ZeroMQ still expose today, letting unrelated processes exchange structured, typed messages without the strict FIFO-only constraint of a pipe. The kernel persistence this task highlights is a double-edged sword in practice: forgotten message queues from crashed test programs are a classic source of /proc/sys/kernel/msgmni exhaustion on long-running Linux servers, which is exactly why ipcs/ipcrm exist.
Before you call the implementation done, walk failure modes on purpose. Test empty structures, single-element edge cases, maximum concurrency, and errno paths that must not crash the program. OS code usually fails in production when happy-path tests pass but invariants break under contention or memory pressure.
Keep structures small and name fields after kernel counterparts when possible. That lets you read man pages and kernel source side by side while you work. Print observable events during development; remove noisy logs once tests pass reliably.
You will implement send and receive with blocking on empty queues. The task asks you to handle partial queue limits and return EAGAIN on non-blocking full queue.
Exchange typed messages through a System V message queue. Unlike a pipe, a queue keeps message boundaries, and a receiver can select messages. msgrcv with type 0 takes the oldest message. A positive type takes the oldest message of exactly that type. A negative type −T takes the message with the lowest type ≤ T (oldest first among equals), which turns the queue into a priority queue. A producer process sends; the consumer receives with different selectors.
cLoading…
msgget(IPC_PRIVATE, IPC_CREAT | 0600).send line, in input order, with msgsnd, then exits with status = the number of messages sent. It prints nothing.producer sent N messages. Then it handles every recv/count line in input order:
recv SEL → msgrcv(..., SEL, IPC_NOWAIT), printing recv SEL: type T "TEXT" or recv SEL: no message (ENOMSG).count → msgctl(IPC_STAT), printing queue: N messages.msgctl(IPC_RMID) and print queue removed (N messages discarded).The message struct is struct { long mtype; char mtext[128]; }, and msgsnd gets the text length including its terminating NUL. The total text stays under 1 KiB, well within every system's queue limit.
Input:
cLoading…
Output:
cLoading…
IPC_NOWAIT on every receive, so an empty selection reports no message instead of blocking forever. Some systems (macOS among them) implement a negative msgtyp incorrectly, so implement recv −T portably: try msgrcv with type 1, 2, …, T and take the first message found.Hidden tests cover exact-type selection that skips older messages of other types, negative selectors (including one that matches nothing), a type with no messages, and messages left in the queue at the end.