如何在两个进程之间协调共享内存

时间:2014-12-06 21:35:03

标签: c shared-memory

我有程序A和程序B.程序A创建一个队列,用shmget存储到共享内存中,然后是shmat。进程B启动,然后使用相同的shmid获取进程A没有问题的队列。进程A(显然A和B同时运行)然后运行一个修改队列中某个元素的方法。当程序A这样做时,指向该内存块的指针给我一个分段错误。可能是因为程序B现在有指向它的指针我想。 我的问题是如何解决这个问题,以便程序A可以编辑和读取队列以及程序B.我知道我需要某种锁,但不知道什么样的锁是最好的或如何正确实现这个。如果您可以提供一些示例代码以配合您的解释,这将有很大帮助。我正在用C语言编写所有这些,进程A有2个键,一个到队列,另一个到一个数组,为程序B的共享内存中分配的每个段保存所有的shmid,供程序B使用那个信息。

1 个答案:

答案 0 :(得分:1)

我同意评论可能有更好的方法来解决潜在的问题,例如:用管道。但是,由于我的测试代码完全符合您的描述,因此我将与您分享。请注意,运行此代码时,应始终在启动客户端之前启动服务器。

除共享内存外,代码还会创建一对信号量。客户端使用REQUEST_SEM向服务器发出数据可用信号。服务器使用RESPONSE_SEM表示已完成客户端的请求。

如果您决定更改共享内存的大小,则需要使用ipcrm命令删除以前分配的共享内存。另一个有用的命令是ipcs,它列出了您创建的IPC对象。

最后一点说明。使用硬编码的key是不好的。有关生成ftok的更好方法,请参阅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" );
}