Eddi3
Eddi3

Reputation: 59

How to coordinate shared memory between 2 processes

I have program A and program B. Program A makes a queue that's stored into the shared memory with shmget, then shmat. Process B starts up and then uses the same shmid to obtain the queue that process A made without a problem. Process A (both A and B are running at the same time obviously) then runs a method that modifies a certain element in the queue. When program A does this, the pointer to that memory block gives me a segmentation fault. probably because program B now has the pointer pointing to it I suppose. My question is how can I fix this so that program A can edit and read from queue as well as program B. I know that I need some sort of locks but don't know what kind of lock would be best or how to correctly implement this. If you can put up some example code to go along with your explanation that would help a lot. I'm writing all of this in C by the way and process A has 2 keys, one to the queue and another to an array holding all the shmids for every segment allocated in shared memory from Program A to be used by program B to retrieve that information.

Upvotes: 1

Views: 3006

Answers (1)

user3386109
user3386109

Reputation: 34829

I agree with the comment that there may be better ways to solve the underlying problem, e.g. with pipes. However, since I have test code that does exactly what you describe, I'll share it with you. Note that when running this code, you should always start the server before starting the client.

The code creates a pair semaphores in addition to the shared memory. The REQUEST_SEM is used by the client to signal the server that data is available. The RESPONSE_SEM is used by the server to indicate that it's done with the client's request.

If you decide to change the size of the shared memory, you'll need to use the ipcrm command to remove the previously allocated shared memory. Another useful command is ipcs, which lists the IPC objects that you've created.

One final note. Using a hardcoded key is bad. See the documentation for ftok for a better way to generate a key.

Server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>

#define REQUEST_SEM   0
#define RESPONSE_SEM  1

#define SEM_RA    (SEM_R | SEM_A)
#define SEM_FLAGS (SEM_RA | (SEM_RA >> 3) | (SEM_RA >> 6))
#define MEM_RW    (SHM_R | SHM_W)
#define MEM_FLAGS (MEM_RW | (MEM_RW >> 3) | (MEM_RW >> 6))

static void error( const char *msg )
{
    perror( msg );
    exit( 1 );
}

void waitForIt( int semid, int semnum )
{
    struct sembuf operations = { semnum, -1, 0 };

    if ( semop( semid, &operations, 1 ) < 0 )
        error( __func__ );
}

void signalIt( int semid, int semnum )
{
    struct sembuf operations = { semnum, 1, 0 };

    if ( semop( semid, &operations, 1 ) < 0 )
        error( __func__ );
}

int main( int argc, char *argv[] )
{
    int i, semID, memID, good, bad;
    char *memAddress;

    if ( (semID = semget( 0x1001, 2, IPC_CREAT | SEM_FLAGS )) < 0 )
        error( "Unable to create semaphores" );
    if ( semctl( semID, REQUEST_SEM, SETVAL, 0 ) < 0 )
        error( "Unable to initialize request semaphore" );
    if ( semctl( semID, RESPONSE_SEM, SETVAL, 0 ) < 0 )
        error( "Unable to initialize response semaphore" );

    if ( (memID = shmget( 0x1001, 1024, IPC_CREAT | MEM_FLAGS )) < 0 )
        error( "Unable to create shared memory" );
    memAddress = shmat( memID, NULL, 0 );    
    if ( memAddress == NULL || memAddress == ((void *) -1) )
        error( "Unable to attach shared memory" );

    good = 0;
    bad  = 0;
    for ( i = 0; i < 100; i++ )
    {
        waitForIt( semID, REQUEST_SEM );
        if ( memAddress[0] == i )
            good++;
        else
            bad++;

        memAddress[0] = 0x55;
        signalIt( semID, RESPONSE_SEM );
    }

    printf( "good=%d bad=%d\n", good, bad );

    if ( shmdt( memAddress ) < 0 )
        error( "Unable to detach shared memory" );
}

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>

#define REQUEST_SEM   0
#define RESPONSE_SEM  1

static void error( const char *msg )
{
    perror( msg );
    exit( 1 );
}

void waitForIt( int semid, int semnum )
{
    struct sembuf operations = { semnum, -1, 0 };

    if ( semop( semid, &operations, 1 ) < 0 )
        error( __func__ );
}

void signalIt( int semid, int semnum )
{
    struct sembuf operations = { semnum, 1, 0 };

    if ( semop( semid, &operations, 1 ) < 0 )
        error( __func__ );
}

int main( void )
{
    int i, semID, memID, good, bad;
    char *memAddress;

    if ( (semID = semget( 0x1001, 0, 0 )) < 0 )
        error( "Unable to get semaphores" );

    if ( (memID = shmget( 0x1001, 0, 0 )) < 0 )
        error( "Unable to create shared memory" );
    memAddress = shmat( memID, NULL, 0 );
    if ( memAddress == NULL || memAddress == ((void *) -1) )
        error( "Unable to attach shared memory" );

    good = 0;
    bad  = 0;
    for ( i = 0; i < 100; i++ )
    {
        memAddress[0] = i;
        signalIt( semID, REQUEST_SEM );

        waitForIt( semID, RESPONSE_SEM );
        if ( memAddress[0] == 0x55 )
            good++;
        else
            bad++;
    }

    printf( "good=%d bad=%d\n", good, bad );

    if ( shmdt( memAddress ) < 0 )
        error( "Unable to detach shared memory" );
}

Upvotes: 2

Related Questions