Skip to content

POSIX Queues in C: A Complete Guide to Understand and Implement

POSIX Queues and messages

Message queues are an essential form of Inter-Process Communication (IPC) used in various applications, such as task scheduling, buffering data between processes or threads, and managing requests in web servers. This article will explore POSIX queues, a type of message queue provided by the POSIX standard, and walk you through the process of using them in C programming with a practical example.

What Are Queues?

A queue is a linear data structure that stores a collection of elements. In a queue, elements are added (enqueued) to the rear and removed (dequeued) from the front following a First-In-First-Out (FIFO) order. Queues are commonly used to manage tasks in a sequential manner, simulating real-world scenarios like waiting in line.

This article explains queues and their implementation in C.

Introduction to POSIX Queues

POSIX queues, also known as message queues, enable separate processes to send and receive messages in a synchronized manner. Messages are stored in a queue and retrieved following the FIFO order. POSIX queues are useful for synchronizing communication between different processes in an efficient manner.

Key Functions for Working with POSIX Queues

To work with POSIX queues, you’ll need to familiarize yourself with the following functions:

  1. mq_open(): Opens or creates a message queue.
  2. mq_close(): Closes a message queue.
  3. mq_unlink(): Removes a message queue.
  4. mq_send(): Sends a message to the queue.
  5. mq_receive(): Receives a message from the queue.

Syntax and Parameters

Here’s a brief explanation of the syntax and parameters for each function:

  • mq_open(): mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
    • name: The name of the message queue.
    • oflag: The flags for opening the queue (e.g., O_CREAT, O_WRONLY, O_RDONLY).
    • mode: The permissions for the queue.
    • attr: A pointer to a mq_attr structure that specifies the queue’s attributes.
  • mq_close(): int mq_close(mqd_t mqdes);
    • mqdes: The message queue descriptor.
  • mq_unlink(): int mq_unlink(const char *name);
    • name: The name of the message queue.
  • mq_send(): int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);
    • mqdes: The message queue descriptor.
    • msg_ptr: A pointer to the message to be sent.
    • msg_len: The length of the message.
    • msg_prio: The message priority.
  • mq_receive(): ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio);
    • mqdes: The message queue descriptor.
    • msg_ptr: A pointer to the buffer where the received message will be stored.
    • msg_len: The length of the buffer.
    • msg_prio: A pointer to the variable where the message priority will be stored.

Example: Using POSIX Queues for Inter-Process Communication

The following example demonstrates the usage of POSIX queues for communication between two processes: a sender and a receiver. We’ll provide separate code snippets for each process and explain the code using comments.

Sender Process

#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h

int main() {
    mqd_t mq;
    struct mq_attr attr;
    char buffer[1024];

    // Initialize the queue attributes
    attr.mq_flags = 0;
    attr.mq_maxmsg = 10;
    attr.mq_msgsize = 1024;
    attr.mq_curmsgs = 0;

    // Open or create the message queue
    mq = mq_open("/my_queue", O_CREAT | O_WRONLY, 0644, &attr);
    if (mq == -1) {
        perror("mq_open");
        exit(1);
    }

    // Send a message to the queue
    strcpy(buffer, "Hello, world!");
    if (mq_send(mq, buffer, strlen(buffer), 0) == -1) {
        perror("mq_send");
        exit(1);
    }

    // Close the message queue
    if (mq_close(mq) == -1) {
        perror("mq_close");
        exit(1);
    }

    return 0;
}

Receiver Process

#include <fcntl.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    mqd_t mq;
    char buffer[1024];

    // Open the message queue
    mq = mq_open("/my_queue", O_RDONLY);
    if (mq == -1) {
        perror("mq_open");
        exit(1);
    }

    // Receive a message from the queue
    if (mq_receive(mq, buffer, 1024, NULL) == -1) {
        perror("mq_receive");
        exit(1);
    }

    printf("Received: %s\n", buffer);

    // Close the message queue
    if (mq_close(mq) == -1) {
        perror("mq_close");
        exit(1);
    }

    // Remove the message queue
    if (mq_unlink("/my_queue") == -1) {
        perror("mq_unlink");
        exit(1);
    }

    return 0;
}

Compiling and Running the Code

To compile and run the code, follow these steps:

  • Save the sender process code in a file named sender.c and the receiver process code in a file named receiver.c.
  • Compile both files using the following commands:
gcc -o sender sender.c -lrt
gcc -o receiver receiver.c -lrt
  • Run the sender and receiver processes separately in two different terminal windows:
./sender
./receiver

The receiver process should output the message sent by the sender process: “Hello, world!”.

In conclusion, POSIX queues provide a powerful and efficient way to facilitate communication between different processes in C programming. By understanding the syntax and parameters of key functions and following the provided example, you can easily implement and use POSIX queues in your own projects.

Leave a Reply

Your email address will not be published. Required fields are marked *