Writing Shared Multi-Queue

<< prev next >>

This example shows how to write to a shared multi-queue using the Shared Memory Arena library.

A Shared Multi-Queue object (smq) is queue that is built using a shared memory segment(s). So the queue is shared between unrelated processes (or related). The queue is a multi-queue in that all queue objects may read all the data in the queue. It's like all objects in all threads (or processes) can read all the data that was ever written. Shared Multi-Queues use a circular buffer, and so they never fill up, but they do over-write old entries so the queue length, program read and write rates must be made compatible, so know your limiting time rates and don't waste memory.

First lets run this program and see what it does.

In a shell (bash, csh, tcsh) from the directory examples/tutorial/ in two different terminals run:
./smq_write
and
./smq_read

You can send signal INT (Ctrl-C) to terminate the either program. You can run more or less of either program. See if you can figure out what going on.

Looking at the Source

From examples/tutorial/smq_write.c

First we include some header files:

#include <unistd.h> /* for usleep() */
#include <signal.h> /* for signal() */
#include <shm_arena.h> /* for Shared Memory Arena Library */
static int running = 1;

We will use a signal catcher function to terminate the program by un-setting the running flag.

static void catcher(int sig)
{
printf("catch signal %d\n", sig);
running = 0;
}
int main(void)
{
smq_t q;
int count = 0;
int *ptr;
signal(SIGINT, catcher);

We get a Shared Multi-Queue object. The Shared Multi-queue's entry size is sizeof(int), it will have a queue length of at least 10, and its name is "q_count". smq_get() will also get an arena object too.

q = smq_get(NULL, sizeof(int), 10, "q_count", O_CREAT);
if(!q)
{
printf("smq_get() failed\n");
return 1;
}

There is no need to initialize the queue as with a shared memory segment because the reader will see there are no entries in the queue when reading, if there are none.

We then loop write-locking, writing, unlocking, and sleeping until running is zero:

while(running)
{
smq_wrlock(q, 0);
/* get the next entry to write */
ptr = smq_write(q);
/* write */
*ptr = count;
count++;
usleep(100000); /* micro seconds */
}
return 0;
}

Clearly the usleep() call is just used to keep this example code simple. Such a call should be avoided in good production code.

This is not much different than writing to a shared memory segment except that the data is written in chunks of entries and the entries are queued. That is why we must get the pointer, ptr, for each write we do, since the returned pointer points to a different queue address for each smq_write() call. The data is not lost by being over-written unless the reader is too slow to read the entries before the queue wraps, overwriting entries that have not been read yet. Any number of readers can start reading the queue entries at any time. All the reader objects will be able to get all the data assuming the queue is large enough for the rates that they are reading and writing. Of course, there may be any number of writers too.

<< prev next >>


Shared Memory Arena version RC-0.0.25