在分叉进程之间共享运行时创建的对象
Sharing an object created at runtime between forked processes
我有一个节点 class,它包含两个嵌套的 classes,服务器和客户端,以及指向每个实例的指针。
我在父进程中对我的节点执行一些初始化方法,但希望嵌套的服务器和客户端实例独立运行。
我目前的方法是使用 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 的完全相同的副本?
更新:
我尝试避免使用双指针,并更改了一些小的东西。我遇到了 placement new 运算符,并认为这将允许我在 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 序列,但没有效果。有没有一种机制可以用来强制我的 class 分配共享内存段中的所有数据?
我觉得这可以做到,但我不知道如何做,我想这可能很困难。有什么想法吗?
您没有共享节点对象,每个进程都有自己的节点副本。它们在分叉时是相同的,但一个进程中的更改不会反映在另一个进程中。为此,您必须实际实例化共享内存中的节点对象。你需要做一个 'placement new'
我有一个节点 class,它包含两个嵌套的 classes,服务器和客户端,以及指向每个实例的指针。
我在父进程中对我的节点执行一些初始化方法,但希望嵌套的服务器和客户端实例独立运行。
我目前的方法是使用 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 的完全相同的副本?
更新:
我尝试避免使用双指针,并更改了一些小的东西。我遇到了 placement new 运算符,并认为这将允许我在 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 序列,但没有效果。有没有一种机制可以用来强制我的 class 分配共享内存段中的所有数据?
我觉得这可以做到,但我不知道如何做,我想这可能很困难。有什么想法吗?
您没有共享节点对象,每个进程都有自己的节点副本。它们在分叉时是相同的,但一个进程中的更改不会反映在另一个进程中。为此,您必须实际实例化共享内存中的节点对象。你需要做一个 'placement new'