Problems with shared memory to communicate between two Linux tasks...

From: doc_rudolph (fjr_at_controlsmith.com)
Date: 06/28/05


Date: 27 Jun 2005 19:14:53 -0700

I recently tried to use shared memory to communicate between two Linux
tasks...

I am using RHEL 9.0

I used as a model the programs in the "Beginning Linus Programming"
text by Stones and Matthew.

The source repository, published by Wrox is found here:
http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764544977,descCd-download_code.html

In generaly this code repository has been an excellent toolkit for
getting kickstarted on various Linux methodologies.

This time I am stumped.

I used the example from chapter 13 of the source repository. In it a
program called shm1.c is a consumer and shm2.c is the producer. When I
compiled the code it worked first time, no problem. So I started
modifying the code and making it more complex until finally I got an
error message on Shmget with errno = EINVAL.

This means various things, according to whom you ask, from memory
segment too big, to invalid command. Neither is the case, however,
because the size is between 64 and 200 bytes, and the cmd is the same
throughout all my attempts.

I started backing out my changes and the error persisted until finally
I was back to the original code and the error still persisted. I was in
denial at this poitn, so I downloaded a virgin copy of the chapter 13
code and tried again. I still get the error.

I found that I could eliminate the error by rebooting my computer.

I thought perhaps I was not being careful enough about graceful
terminations while developing the code and was suffering from meory
leaks, but that seems not to be the case because I have had this
problem randomly, never immediately after reboot, but sometimes after
the 2nd try and sometimes after the 20th try. Once the error shows up,
however, it is absolutely persistent and I must reboot to eliminate it.

Anyone ever had this problem?
I am attaching the example code from chapter 13, below

Sincerely,
Frank Rudolph
fjr@controlsmith.com

Here is the "consumer":
/* Our first program is a consumer. After the headers the shared memory
segment
 (the size of our shared memory structure) is created with a call to
shmget,
 with the IPC_CREAT bit specified. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include "shm_com.h"

int main()
{
    int running = 1;
    void *shared_memory = (void *)0;
    struct shared_use_st *shared_stuff;
    int shmid;

    srand((unsigned int)getpid());

    shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 |
IPC_CREAT);

    if (shmid == -1) {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

/* We now make the shared memory accessible to the program. */

    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1) {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }

    printf("Memory attached at %X\n", (int)shared_memory);

/* The next portion of the program assigns the shared_memory segment to
shared_stuff,
 which then prints out any text in written_by_you. The loop continues
until end is found
 in written_by_you. The call to sleep forces the consumer to sit in its
critical section,
 which makes the producer wait. */

    shared_stuff = (struct shared_use_st *)shared_memory;
    shared_stuff->written_by_you = 0;
    while(running) {
        if (shared_stuff->written_by_you) {
            printf("You wrote: %s", shared_stuff->some_text);
            sleep( rand() % 4 ); /* make the other process wait for us
! */
            shared_stuff->written_by_you = 0;
            if (strncmp(shared_stuff->some_text, "end", 3) == 0) {
                running = 0;
            }
        }
    }

/* Lastly, the shared memory is detached and then deleted. */

    if (shmdt(shared_memory) == -1) {
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }

    if (shmctl(shmid, IPC_RMID, 0) == -1) {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

Here is the "producer":
/* The second program is the producer and allows us to enter data for
consumers.
 It's very similar to shm1.c and looks like this. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include "shm_com.h"

int main()
{
    int running = 1;
    void *shared_memory = (void *)0;
    struct shared_use_st *shared_stuff;
    char buffer[BUFSIZ];
    int shmid;

    shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 |
IPC_CREAT);

    if (shmid == -1) {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1) {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }

    printf("Memory attached at %X\n", (int)shared_memory);

    shared_stuff = (struct shared_use_st *)shared_memory;
    while(running) {
        while(shared_stuff->written_by_you == 1) {
            sleep(1);
            printf("waiting for client...\n");
        }
        printf("Enter some text: ");
        fgets(buffer, BUFSIZ, stdin);

        strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
        shared_stuff->written_by_you = 1;

        if (strncmp(buffer, "end", 3) == 0) {
                running = 0;
        }
    }

    if (shmdt(shared_memory) == -1) {
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

and here is the shared memory header file, shm_com.h:

/* A common header file to describe the shared memory we wish to pass
about. */

#define TEXT_SZ 2048

struct shared_use_st {
    int written_by_you;
    char some_text[TEXT_SZ];
};


Quantcast