通过共享内存IPC在进程之间共享指针

时间:2012-12-22 01:45:45

标签: c++ linux pointers ipc shared-memory

我试图通过共享内存在父级和分叉子级之间共享已定义类的指针。

所以在父母的主要创建指针

mydata *p;
Reader::GetInstance()->Read(p, i+1);
        pid = fork();
        if (pid == -1){
            cout << "error on fork"<<endl;
        }else if (pid == 0){
            cout << "i will fork now" <<endl;
            const char * path = "./mydatamanager";
            execl (path, "-", (char *)0);
            break;
        }else {
            writer(shmid, p);
        }

writer包含此

void writer(int shmid , mydata * p)
{
    void *shmaddr;   
    shmaddr = shmat(shmid, (void *)0, 0);
    if((int)shmaddr == -1)
    {   
        perror("Error in attach in writer");
        exit(-1);
    }
    else
    {
        memcpy( shmaddr, p, sizeof(*p) );
    }   
}

我的数据是

    class mydara {
    public:
        int var1;
        int var2;
        int var3;
        int var4;
        int var5;
        int var6;
        char *var7;
mydata (int v2, int v3,char *v7, int v6){
        var2 = v2;
        var3 = v3;
        var7 =new char[128];
        strcpy(var7, v7);
        var6 = v6;
        var4 = 0;
        var5 = 0;
    }
    };

并且在mydatamanager中我以这种方式得到这个指针

void reader(int shmid, mydata *& p)
{
    cout << "in reader" << endl;
    void *shmaddr;

      //sleep(3);

    shmaddr = shmat(shmid, (void *)0, SHM_RDONLY|0644);
    if((int)shmaddr == -1)
    {   
        perror("Error in reader");
        exit(-1);
    }
    else
    {
        cout << "in else "<< endl;
        p = (mydata*) shmaddr;
        cout <<"shared memory address is " <<shmaddr <<endl;
        cout <<"var5 "<< p->var5<< endl;
        cout <<"var2 "<< p->var2<< " match with "<<getpid() << "?" << endl;
        cout <<"var3 "<< p->var3<< endl;
        cout <<"var4 "<< p->var4<< endl;
        cout <<"var7 "<< p->var7<< endl; // the 
        //shmdt(shmaddr);
    }
}

和mydatamanager main:

int main()
{
    cout << "in main" <<endl;
    int shmid;
    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0644);
    cout << "in advanced point" <<endl;
    sleep(1);
    mydata * p;
    reader (shmid, p);
    cout << p->var7 <<endl;
    return 0;
}

结果始终为0。 我如何通过父和子共享此指针以及我的代码中的错误在哪里?

3 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

首先,你没有同步任何东西。那你怎么知道哪个先跑,读者或作家。在新分配的块中,内存必然为零,因此结果为零。

任何共享内存必须确保读者在读者完成(至少部分)写入过程之前不会阅读。

小心分享课程 - 你不能使用虚拟功能,因为这几乎肯定会做一些你所期望的事情(崩溃,很可能,但其他选项都可用,没有一个特别令人愉快)

答案 2 :(得分:0)

处理问题的最简单方法是在 fork之前在父进程中创建一个信号量,让子进程在之前尝试获取它读取(而不是执行sleep)并且父进程在写入之后将其释放

首先,这里有创建,销毁和检索信号量id的函数:

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


int create_semaphore(const char *path, char id, int count){
    key_t k = ftok(path, id);
    semid = semget(k, 1, IPC_CREAT | IPC_EXCL | 0600);
    semctl(semid, 0, SET_VAL, count);
    return semid;
}

int destroy_semaphore(int semid){
    semctl(semid, 0, IPC_RMID, 0);
}

int get_semaphore(const char *path, char id){
    key_t k = ftok(path, id);
    semid = semget(k, 1, 0600);
    return semid;
}

现在我们需要一个函数来获取它,另一个函数来释放它:

void acquire_semaphore(int semid){
    sembuf op;
    op.sem_num = O;
    op.sem_op = -1;
    op.sem_flg = 0;
    semop(semid,&op,1);
}

void release_semaphore(int semid){
    sembuf op;
    op.sem_num = 0;
    op.sem_op = 1;
    op.sem_flg = 0;
    semop(semid,&op,1);
}

使用这些样板功能,您应该能够同步您的过程。

因此,您需要提供路径和唯一ID(以简单字符的形式)来创建和识别您的信号量。如果您已使用ftok创建共享内存ID(shmid),则应了解该想法。否则,只需确保两个进程中的两个值都相同。

在您的编写器代码中,输入以下行:

 semid = create_semaphore(argv[0], 'S', 0);

pid = fork();行之前,同时创建和获取信号量。

添加以下行:

 release_semaphore(semid);

在发出信号量的writer(shmid, mydata);指令之后。您还需要在范围内的某处声明semid。我使用编写器程序路径来创建信号量,这是确保没有其他进程已经使用我们的路径的好习惯。唯一的问题是你需要确保读者使用相同的路径。您可以在读者代码中的某个位置对该值进行硬编码,或者更好的是,将其从execl参数中的作者传递(左侧作为练习)。

假设读者已知path,剩下要做的就是获取信号量似的:

semid = get_semaphore(path, 'S');
acquire_semaphore(semid);
destroy_semaphore(semid);

在读者reader(shmid, mydata);函数中的行main之前

正如其他帖子所说,通过共享内存段共享类实例通常是非常糟糕的主意。它更安全 传递简单的struct数据,并在阅读器端重建您的对象(在网上查找序列化和编组以获取更多信息)。

询问您是否遇到此(未经测试)代码的问题。

圣诞快乐!