Wednesday, September 10, 2014

How to use shared memory for process intercommunication on Linux?

On Linux intercommunication with using shared memory API is more elegant than on Windows.

Shared memory server


Example sequence of calls for shared memory server is:
  1. Call ftok function and receive key for shared memory segment.
  2. Call shmget with IPC_CREAT to create new shared memory segment.
  3. Call shmat to attach to shared memory array. Do some operations with shared memory.
  4. Call shmdt to detach from shared memory array.
  5. Call shmctl with IPC_RMID to remove shared memory segment.
Here is an example of shared memory server which writes Hello World message to shared memory and waits for pressing of any key:

#include <stdio.h>

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <cstring>
#include <fcntl.h>

int main(int argc, char ** argv)
{
        key_t key = ftok(argv[0], 1);
        if (key < 0)
        {
                perror("ftok"); /*Displays the error message*/
                return -1;
        }

        printf("Key for shared memory: '%s'\n", argv[0]);

        int shmid = shmget(key, 4096,  IPC_CREAT | O_EXCL | S_IRUSR | S_IWUSR);
        if(shmid == -1)
        {
                fprintf(stderr, "Failed to create memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        void * pAddr = shmat(shmid, NULL, 0);
        if((long long )pAddr == -1)
        {
                if(shmctl(shmid, IPC_RMID, NULL) == -1)
                {
                        fprintf(stderr, "Failed to remove shared memory segment. %s\n", 
                                strerror(errno));
                        return -1;
                }

                fprintf(stderr, "Failed to attach to shared memory. %s\n", 
                        strerror(errno));
                return -1;
        }

        const char * szcServerMessage = "Hello world!";
        strcpy((char *) pAddr, szcServerMessage);

        printf("Server put message to shared memory.\n");
        printf("Press any key for exit ...\n");
        getchar();

        if(shmdt(pAddr) == -1)
        {
                fprintf(stderr, "Failed to detach from shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        if(shmctl(shmid, IPC_RMID, NULL) == -1)
        {
                fprintf(stderr, "Failed to remove shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        return 0;
}

Shared memory client

Example sequence of calls for shared memory client is:
  1. Call ftok function and receive key for shared memory segment.
  2. Call shmget to obtain pointer to existing shared memory segment descriptor.
    Don't set IPC_CREAT flag, besides instead memory size you can simply pass 0.
  3. Call shmat to attach to shared memory array. Do some operations with shared memory.
  4. Call shmdt to detach from shared memory array.
Please notice that on client side you shouldn't call shmctl with IPC_RMID, because shared segment was created on server side, but not on client.

Here is implementation of shared memory client that attaches to the shared memory segment and then reads message:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <cstring>
#include <fcntl.h>

int main(int argc, char ** argv)
{
        key_t key = ftok("./server", 1);
        if (key < 0)
        {
                perror("ftok"); /*Displays the error message*/
                return -1;
        }

        int shmid = shmget(key, 0,  S_IRUSR | S_IWUSR);
        if(shmid == -1)
        {
                fprintf(stderr, "Failed to create memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        void * pAddr = shmat(shmid, NULL, 0);
        if((long long )pAddr == -1)
        {
                fprintf(stderr, "Failed to attach to shared memory. %s\n", 
                        strerror(errno));
                return -1;
        }

        char szcBufferMessage[4096];
        strcpy(szcBufferMessage, (char *) pAddr);

        printf("Client read message from shared memory: %s \n", szcBufferMessage);
        printf("Press any key for exit ...\n");
        getchar();

        if(shmdt(pAddr) == -1)
        {
                fprintf(stderr, "Failed to detach from shared memory segment. %s\n", 
                        strerror(errno));
                return -1;
        }

        /* In client we shouldn't delete any segment, because it is allocated by server */

        return 0;
}

Server's output example:

$ ./server
Key for shared memory: './server'
Server put message to shared memory.
Press any key for exit ...

Client's output example:

$ ./client
Client read message from shared memory: Hello world! 
Press any key for exit ...

As you can see client successfully reads the message from server.
Hope this post is useful. Good luck!

No comments:

Post a Comment