Can I send and receive multiple structs in message queues in IPC mechanism?

67 Views Asked by At

I'm exploring message queue implementations in [insert programming language], and I'm curious about the possibility of sending multiple structs through a message queue. Specifically, I would like to understand the feasibility of enqueuing and dequeuing multiple instances of a struct type. If this is possible, are there any considerations or best practices I should be aware of to ensure smooth data handling within the message queue?

#include <stdlib.h>
 
// Define a sample struct
struct MyStruct {
    int data;
};
 
// Define a node structure for the queue
struct Node {
    struct MyStruct *item;
    struct Node *next;
};
 
// Define the queue structure
struct Queue {
    struct Node *front;
    struct Node *rear;
};
 
// Function to initialize an empty queue
struct Queue* createQueue() {
    struct Queue* queue = (struct Queue*)malloc(sizeof(struct Queue));
    queue->front = queue->rear = NULL;
    return queue;
}
 
// Function to enqueue a struct into the queue
void enqueue(struct Queue* queue, struct MyStruct *data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->item = data;
    newNode->next = NULL;
 
    if (queue->rear == NULL) {
        queue->front = queue->rear = newNode;
    } else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
}
 
// Function to dequeue a struct from the queue
struct MyStruct* dequeue(struct Queue* queue) {
    if (queue->front == NULL) {
        return NULL; // Queue is empty
    }
 
    struct Node* temp = queue->front;
    struct MyStruct* data = temp->item;
 
    queue->front = temp->next;
 
    if (queue->front == NULL) {
        queue->rear = NULL;
    }
 
    free(temp);
    return data;
}
 
int main() {
    // Create a queue
    struct Queue* myQueue = createQueue();
 
    // Create and enqueue multiple structs
    struct MyStruct struct1 = {10};
    struct MyStruct struct2 = {20};
 
    enqueue(myQueue, &struct1);
    enqueue(myQueue, &struct2);
 
    // Dequeue and print the structs from the queue
    struct MyStruct* retrievedStruct1 = dequeue(myQueue);
    struct MyStruct* retrievedStruct2 = dequeue(myQueue);
 
    printf("Struct 1: %d\n", retrievedStruct1->data); // Output: 10
    printf("Struct 2: %d\n", retrievedStruct2->data); // Output: 20
 
    // Don't forget to free memory if needed
    free(retrievedStruct1);
    free(retrievedStruct2);
    
    return 0;
}```

This question not off topic to electronics but which is related to rtos IPC mechanism
1

There are 1 best solutions below

0
Lundin On

Specifically, I would like to understand the feasibility of enqueuing and dequeuing multiple instances of a struct type. If this is possible, are there any considerations or best practices I should be aware of to ensure smooth data handling within the message queue?

The code you've posted looks pretty much like a standard example from some algorithm/data structure class. Yes, you can write code such as this, obviously. The real question is - should you? And that's where best practices come in too.

You originally posted this on Electrical Engineering and tagged it with FreeRTOS so I'll assume you are coding an embedded system. Using dynamic allocation in such a system is generally senseless, for a great number of reasons described here: Why should I not use dynamic memory allocation in embedded systems?

But even outside the scope of embedded systems, these old school data structure implementations, like the average school book linked list, that use individual malloc calls originate from the dark ages somewhere (or from the 1980s at least). A time before cache memories were invented and became mainstream on the PC side of things, which happened in the early 1990s.

What this means is that individual malloc calls in almost every context are very expensive. Both in pure function call overhead (if you like to stare into the Abyss, check out how heap allocation is implemented in the Linux kernel) as well in access time, because you aren't allocating data in contiguous memory, but rather allocate it segmented all over the place.

Therefore the proper implementation of linked lists, queues and the like no matter system is often to use a fixed size buffer/table in the form of an array. You keep track of which items in the buffer that are empty and which ones contain data. You keep track of the total size. "Next pointers" are replaced with integer indices. This is fast, easy to implement, cache-friendly and without all the problems of dynamic allocation.

Back in the dark ages, then supposedly it was expensive to add/remove items in the middle of an array because you have to move around all the data, and linked lists were presented as the solution to this. But on a modern x86_64, it will chew through raw data copies like nothing, whereas it will struggle far more following a linked list through some scenic route all over the heap.


As for the RTOS or IPC aspect, it's like any other variable - you need some means of synchronization/protection. Semaphore, mutex, critical section etc. You could integrate that in the queue itself or place it outside it, whatever makes most sense for your purposes.