2

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

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

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);
        }

作家包含这个

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。我如何通过父母和孩子分享这个指针,我的代码中的错误在哪里?

4

3 回答 3

1

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

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

小心共享类——你不能使用虚函数,因为这几乎肯定会做一些超出你预期的事情(很可能会崩溃,但还有其他选项可用,但没有一个特别令人愉快)

于 2012-12-22T02:20:51.960 回答
0

处理您的问题的最简单方法是在父进程中创建信号量之前fork让子进程尝试在读取之前获取它(而不是执行 a ),并且父进程在写入之后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在范围内的某处声明。我使用 writer 程序路径来创建信号量,这是确保没有其他进程已经使用我们的路径的好习惯。唯一的问题是您需要确保读者将使用相同的路径。您可以将该值硬编码在阅读器代码中的某处,或者更好的是,从execl参数中的编写器传递它(作为练习留下)。

假设path读者知道,剩下要做的就是像这样获取信号量:

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

reader(shmid, mydata);在阅读器功能的行前main

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

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

圣诞节快乐!

于 2012-12-25T09:25:26.400 回答