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

C++ 在分叉进程之间共享运行时创建的对象,c++,shared-memory,C++,Shared Memory,我有一个节点类,它包含两个嵌套类:服务器类和客户端类,以及指向每个类的实例的指针 我对父进程中的节点执行一些init方法,但希望嵌套的服务器和客户机实例独立运行 我当前的方法使用shmget和shmat。 我以前用mmap做过一次不成功的尝试 #include "../hdr/g04.h" #include <sys/shm.h> #include <sys/wait.h> void fatal(string s) { cerr << "Error:

我有一个节点类,它包含两个嵌套类:服务器类和客户端类,以及指向每个类的实例的指针

我对父进程中的节点执行一些init方法,但希望嵌套的服务器和客户机实例独立运行

我当前的方法使用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
        20
server: 0x7f2532683390
        30
parent: 0x7f2532683390
        30

我看到节点的地址是相同的。那很好。但为什么每个子进程中“test”值的变化没有反映在父进程中

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

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


更新:

我试着避免使用双指针,并做了一些小改动。我遇到了placement新操作符,并认为这将允许我在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;
}
#包括
#包括
#包括
#包括
无效致命(字符串s){
如果(错误号)
佩罗尔(s.c_str());
其他的
cerr服务器->测试=20;
测试(“客户端:”,此节点);
//做客户的事情
出口(0);
}
//试验
等待(空);
测试(“父节点:”,此节点);
//创建服务器操作进程
如果((server_pid=fork())<0)致命(“fork”);
如果(服务器\u pid==0){
此节点->服务器->测试=30;
测试(“服务器:”,此节点);
//做服务器的事情
出口(0);
}
//试验
等待(空);
测试(“父节点:”,此节点);
//删除此节点;
返回0;
}
程序运行平稳,但我仍然得到与以前相同的输出

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


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

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


可以帮你吗?是的,这就是我试图用这行代码做的
thisNode=new(nodeLocation)Node()。放置新机制是否需要在我的整个类结构中传播,以便在运行时创建的每个嵌套对象都符合我的要求?我只读了第一遍。但是您的更改是不够的-您想要共享的所有内容(在某种意义上,进程1中的更改将显示在进程2中)都必须在共享内存中。因此,我想我的最后一个问题是:如何“重载”类中的所有分配,以便共享内存块动态扩展,所有的动态对象都在这个空间中分配吗?这不是一个简单的方法——只是在代码中费力地工作。我个人不会这样做。我会制定出必须共享的具体内容,并将其组织成易于共享的结构。例如,没有嵌套类。我恐怕是这样的。嗯,这是一个学校项目,我可能会因为试图优化东西而得意忘形。Tbh我甚至不确定在分岔时间之后我是否需要共享内存。我想我会接受你的建议,在我完全需要某种形式的IPC之前不要管它。谢谢
#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;
}