在分叉进程之间共享在运行时创建的对象

时间:2015-11-13 02:01:58

标签: c++ shared-memory

我有一个Node类,它包含两个嵌套类,Server和Client,以及指向每个类的实例的指针。

我在父进程中对我的Node执行一些init方法,但希望嵌套的Server和Client实例独立行动。

我目前的方法使用shmget和shmat。 我之前使用mmap做了一次非成功的尝试。

#include "../hdr/g04.h"
#include <sys/shm.h>
#include <sys/wait.h>

void fatal(string s) {
    cerr << "Error: " << s << " . . .\n";
    exit(-1);   
}

int main() {

    int shmkey = 12345, shmid;
    Node **nodeLocation, *thisNode;
    pid_t client_pid, server_pid;

    // get a shared mem segment
    if ((shmid = shmget(shmkey, sizeof(Node *), IPC_CREAT | 0666)) < 0)
        fatal("shmget");
    if ((nodeLocation = (Node **) shmat(shmid, NULL, 0)) == (Node **) - 1)
        fatal("shmat");

    // instantiate the Node
    // assign shared memory address
    thisNode = new Node();
    *nodeLocation = thisNode;

    // Node configuration / initialization
    if (configure(*thisNode) < 0) fatal("configuration");
    if (thisNode->read_seeds() < 0) fatal("seed file");
    if (thisNode->read_catalogue() < 0) fatal("catalogue");
    thisNode->init();

    // test
    thisNode->server->test = 10;
    cout << "parent: " << thisNode 
        << "\n\t" << thisNode->server->test << endl;


    // create a client operations process
    if ((client_pid = fork()) < 0) fatal("fork");
    if (client_pid == 0) {

        // test
        thisNode->server->test = 20;
        cout << "client: " << thisNode 
            << "\n\t" << thisNode->server->test << endl;

        // do client stuff
        exit(0);
    }

    // test
    wait(NULL);
    cout << "parent: " << thisNode 
        << "\n\t" << thisNode->server->test << endl;


    // create a server operations process
    if ((server_pid = fork()) < 0) fatal("fork");
    if (server_pid == 0) {

        // test
        thisNode->server->test = 30;
        cout << "server: " << thisNode 
            << "\n\t" << thisNode->server->test << endl;

        // do server stuff
        exit(0);
    }

    // test
    wait(NULL);
    cout << "parent: " << thisNode 
        << "\n\t" << thisNode->server->test << endl;


    delete thisNode;
    return 0;
}

输出:

parent: 0x7f2532683390
        10
client: 0x7f2532683390
        20
parent: 0x7f2532683390
        10
server: 0x7f2532683390
        30
parent: 0x7f2532683390
        10

期望的输出:

parent: 0x7f2532683390
        10
client: 0x7f2532683390
        20
parent: 0x7f2532683390
        20
server: 0x7f2532683390
        30
parent: 0x7f2532683390
        30

我看到Node的地址是一样的。那很好。但是为什么每个孩子的'test'值的变化都没有反映在父流程中?

我的猜测是正在进行上下文切换,因此每个进程都有自己的副本加载到同一地址。

如何更改此设置以便每个进程访问thisNode的完全相同的副本?

更新:

我试过避免双指针,我改变了一些小事。我遇到了贴装新操作符,并认为这样可以让我在shmat提供的地址分配我的对象。

#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <errno.h>

void fatal(string s) {
    if (errno)
        perror(s.c_str());
    else
        cerr << "Error: " << s << " . . .\n";
    exit(-1);   
}

void test(string proc, Node *thisNode) {
    cout << proc << thisNode 
        << "\n\t" << thisNode->server->test << endl;
}

int main() {

    Node *tmp = new Node();
    key_t shmkey;
    int shmid;
    Node *thisNode, *nodeLocation;
    pid_t client_pid, server_pid;

    if ((shmkey = ftok("shared_obj.dat", 'R')) == (key_t)-1)
        fatal("ftok: ");
    if ((shmid = shmget(shmkey, sizeof(*tmp), 0644 | IPC_CREAT)) < 0)
        fatal("shmget: ");
    if ((nodeLocation = (Node *) shmat(shmid, (void *)0, 0)) < 0)
        fatal("shmat: ");
    thisNode = new (nodeLocation) Node();


    // Node configuration / initialization
    if (configure(*thisNode) < 0) fatal("configuration");
    if (thisNode->read_seeds() < 0) fatal("seed file");
    if (thisNode->read_catalogue() < 0) fatal("catalogue");
    thisNode->init();

    // test
    thisNode->server->test = 10;
    test("parent: ", thisNode);

    // create a client operations process
    if ((client_pid = fork()) < 0) fatal("fork");
    if (client_pid == 0) {

        thisNode->server->test = 20;
        test("client: ", thisNode); 
        // do client stuff
        exit(0);
    }

    // test
    wait(NULL);
    test("parent: ", thisNode);


    // create a server operations process
    if ((server_pid = fork()) < 0) fatal("fork");
    if (server_pid == 0) {

        thisNode->server->test = 30;
        test("server: ", thisNode); 
        // do server stuff
        exit(0);
    }

    // test
    wait(NULL);
    test("parent: ", thisNode);


    // delete thisNode;
    return 0;
}

程序运行顺利,但我仍然可以获得与以前相同的输出。

我也在每个子进程中尝试了ftok,shmget,shmat序列但是没有效果。是否有一种机制可以用来强制我的类在共享内存段中分配所有数据?

我觉得可以做到这一点,但我不知道如何并且认为它可能很难。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您不共享节点对象,每个进程都有自己的节点副本。它们在分叉时是相同的,但是一个过程中的变化不会反映在另一个过程中。要实现这一点,您必须实际实例化共享内存中的节点对象。你需要做一个新的&#39;

https://isocpp.org/wiki/faq/dtors#placement-new