Sending a Message to a Queue
Once a POSIX message queue is open, you put messages into it using mq_send(). Unlike System V message queues (which always deliver in FIFO order), POSIX queues support message priorities. Every message has a numeric priority, and higher-priority messages are always received before lower-priority ones — regardless of the order they were sent.
mq_send() Function Signature
int mq_send(
mqd_t mqdes, /* message queue descriptor */
const char *msg_ptr, /* pointer to message buffer */
size_t msg_len, /* length of message in bytes */
unsigned int msg_prio /* message priority (0 = lowest) */
);
/* Returns 0 on success, -1 on error */
| Parameter | Type | Description |
|---|---|---|
mqdes |
mqd_t | Queue descriptor from mq_open() — must be open for writing (O_WRONLY or O_RDWR) |
msg_ptr |
const char * | Pointer to the message data buffer. Can be any binary or text data. |
msg_len |
size_t | Length of the message. Must be ≤ mq_msgsize. Zero-length is allowed. |
msg_prio |
unsigned int | Priority of the message. Higher = more urgent. Range: 0 to MQ_PRIO_MAX−1. |
How Message Priorities Work
Each message has a non-negative integer priority. When a receiver calls mq_receive(), it always gets the oldest message with the highest priority. Within the same priority level, messages are delivered in FIFO order. Priority 0 is the lowest — higher numbers mean higher urgency.
| Receive Order | Message | Priority | Reason |
|---|---|---|---|
| 1st | “B” | 10 | Highest priority |
| 2nd | “A” | 5 | Next priority; sent before “C” |
| 3rd | “C” | 5 | Same priority as “A”, sent after |
| 4th | “D” | 1 | Lowest priority |
Priority Range: MQ_PRIO_MAX
The maximum allowed priority value is defined by the constant MQ_PRIO_MAX (or via sysconf(_SC_MQ_PRIO_MAX)). POSIX requires it to be at least 32. The actual range varies significantly across platforms.
| Platform | MQ_PRIO_MAX | Valid Range |
|---|---|---|
| Linux | 32768 | 0 to 32767 |
| Solaris | 32 | 0 to 31 |
| Tru64 | 256 | 0 to 255 |
| POSIX minimum | 32 | 0 to 31 (guaranteed) |
Error Conditions
| Error | Cause | Fix |
|---|---|---|
EMSGSIZE |
msg_len > mq_msgsize of the queue | Check queue’s mq_msgsize via mq_getattr() before sending |
EAGAIN |
Queue full & O_NONBLOCK set | Retry later or use blocking mode |
EINVAL |
msg_prio ≥ MQ_PRIO_MAX | Use a valid priority value |
EBADF |
mqdes not valid or not open for write | Open with O_WRONLY or O_RDWR |
Blocking vs Non-Blocking Behaviour
When the queue is full (mq_curmsgs == mq_maxmsg), the behaviour of mq_send() depends on the O_NONBLOCK flag:
| O_NONBLOCK | Queue Full Behaviour | Use Case |
|---|---|---|
| NOT set (blocking) | mq_send() blocks (sleeps) until a slot becomes free | Simple pipelines where blocking is fine |
| SET (non-blocking) | Returns immediately with errno = EAGAIN | Event loops, real-time systems, polling |
Code Examples
Example 1: Simple Blocking Send
/* sender.c — sends a single text message with default priority 0 */
/* compile: gcc -o sender sender.c -lrt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mqueue.h>
#include <fcntl.h>
#define QUEUE_NAME "/demo_queue"
#define MSG "Hello from sender"
#define PRIORITY 0
int main(void)
{
mqd_t mqd;
/* Open existing queue for writing (blocking mode) */
mqd = mq_open(QUEUE_NAME, O_WRONLY);
if (mqd == (mqd_t) -1) {
perror("mq_open");
exit(EXIT_FAILURE);
}
/* Send message — will block if queue is full */
if (mq_send(mqd, MSG, strlen(MSG), PRIORITY) == -1) {
perror("mq_send");
mq_close(mqd);
exit(EXIT_FAILURE);
}
printf("Sent: \"%s\" with priority %d\n", MSG, PRIORITY);
mq_close(mqd);
return 0;
}
Example 2: Non-Blocking Send with EAGAIN Handling
/* nonblock_sender.c — uses O_NONBLOCK, retries if queue full */
/* compile: gcc -o nonblock_sender nonblock_sender.c -lrt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <mqueue.h>
#include <fcntl.h>
#define QUEUE_NAME "/demo_queue"
#define MAX_RETRIES 5
int main(void)
{
mqd_t mqd;
const char *msg = "Non-blocking message";
int retries = 0;
/* Open with O_NONBLOCK so mq_send never blocks */
mqd = mq_open(QUEUE_NAME, O_WRONLY | O_NONBLOCK);
if (mqd == (mqd_t) -1) { perror("mq_open"); exit(1); }
while (retries < MAX_RETRIES) {
if (mq_send(mqd, msg, strlen(msg), 5) == 0) {
printf("Sent successfully on attempt %d\n", retries + 1);
break;
}
if (errno == EAGAIN) {
/* Queue is full — wait a bit and retry */
printf("Queue full (attempt %d), retrying...\n", retries + 1);
sleep(1);
retries++;
} else {
/* A real error */
perror("mq_send");
break;
}
}
if (retries == MAX_RETRIES)
fprintf(stderr, "Failed after %d retries\n", MAX_RETRIES);
mq_close(mqd);
return 0;
}
Example 3: Send Messages with Different Priorities
/* priority_sender.c — sends 3 messages with different priorities */
/* compile: gcc -o priority_sender priority_sender.c -lrt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mqueue.h>
#include <fcntl.h>
#define QUEUE_NAME "/prio_queue"
#define MAX_MSG 10
#define MSG_SIZE 128
int main(void)
{
mqd_t mqd;
struct mq_attr attr;
/* Create a fresh queue */
attr.mq_flags = 0;
attr.mq_maxmsg = MAX_MSG;
attr.mq_msgsize = MSG_SIZE;
attr.mq_curmsgs = 0;
mqd = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);
if (mqd == (mqd_t) -1) { perror("mq_open"); exit(1); }
/* Send in this order — but receiver will get them in priority order */
if (mq_send(mqd, "LOW priority msg", 16, 1) == -1) perror("send LOW");
if (mq_send(mqd, "HIGH priority msg", 17, 10) == -1) perror("send HIGH");
if (mq_send(mqd, "MED priority msg", 16, 5) == -1) perror("send MED");
if (mq_send(mqd, "URGENT priority msg",20, 20) == -1) perror("send URGENT");
printf("Sent 4 messages with priorities: 1, 10, 5, 20\n");
printf("Receiver will get them as: URGENT(20), HIGH(10), MED(5), LOW(1)\n");
mq_close(mqd);
return 0;
}
Example 4: Sending a Struct as a Message
/* struct_sender.c — send a C struct as binary message data */
/* compile: gcc -o struct_sender struct_sender.c -lrt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mqueue.h>
#include <fcntl.h>
#define QUEUE_NAME "/struct_queue"
/* Define the message payload structure */
typedef struct {
int sensor_id;
float temperature;
int alarm_level; /* 0=normal 1=warn 2=critical */
} SensorData;
int main(void)
{
mqd_t mqd;
struct mq_attr attr;
SensorData reading = { .sensor_id = 42, .temperature = 38.5f, .alarm_level = 1 };
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = sizeof(SensorData); /* size the queue for our struct */
attr.mq_curmsgs = 0;
mqd = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);
if (mqd == (mqd_t) -1) { perror("mq_open"); exit(1); }
/* Cast struct pointer to char* — mq_send treats it as raw bytes */
if (mq_send(mqd, (char *)&reading, sizeof(reading), reading.alarm_level) == -1) {
perror("mq_send");
mq_close(mqd);
exit(1);
}
printf("Sent sensor data: id=%d temp=%.1f alarm=%d (priority=%d)\n",
reading.sensor_id, reading.temperature,
reading.alarm_level, reading.alarm_level);
mq_close(mqd);
return 0;
}
Example 5: Check Queue Limits Before Sending
/* safe_sender.c — always check mq_msgsize before sending */
/* compile: gcc -o safe_sender safe_sender.c -lrt */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mqueue.h>
#include <fcntl.h>
int safe_send(mqd_t mqd, const char *data, size_t len, unsigned int prio)
{
struct mq_attr attr;
/* Read current attributes to check the size limit */
if (mq_getattr(mqd, &attr) == -1) {
perror("mq_getattr");
return -1;
}
if ((long)len > attr.mq_msgsize) {
fprintf(stderr,
"Error: message size %zu exceeds mq_msgsize %ld\n",
len, attr.mq_msgsize);
return -1;
}
return mq_send(mqd, data, len, prio);
}
int main(void)
{
mqd_t mqd = mq_open("/safe_queue", O_WRONLY);
if (mqd == (mqd_t) -1) { perror("mq_open"); exit(1); }
const char *msg = "Checked message";
if (safe_send(mqd, msg, strlen(msg), 3) == 0)
printf("Message sent safely\n");
mq_close(mqd);
return 0;
}
