共享库、对象构造函数和 fork() 行为
g++(Ubuntu 4.4.3-4ubuntu5)4.4.3。为了清楚起见进行了编辑。
我有一个共享库,我想在第一次加载它时以及每当不再引用它时执行一些操作。
我尝试了两种方法来做到这一点,结果相同。第一个是使用此链接中的建议。第二种是在库内创建类的全局实例。
每个人的工作方式都相同。然后,我构建了一个使用该库并 fork() 关闭进程的测试程序。事实证明,构造函数只被调用一次,但析构函数被调用两次——每个进程调用一次。
这是共享库和 fork() 的预期行为,还是我在这里做错了什么?让 dtor 为每个进程调用而 ctor 只调用一次似乎非常危险。
共享库 (g++ -fPIC -c -o myshare.o myshare.cpp / g++ -shared -o libmyshare.so myshare.o):
class SharedMemAccess
{
public:
SharedMemAccess();
~SharedMemAccess();
};
static SharedMemAccess g_sharedMem;
SharedMemAccess::SharedMemAccess()
{
LOGDEBUG("Constructor\n");return;
}
SharedMemAccess::~SharedMemAccess()
{
LOGDEBUG("Destructor\n");return;
}
测试驱动程序 (g++ -c -o main.o main.cpp / g++ main.o - lmyshare -o test):
int main()
{
LOGDEBUG("In main\n");
pid_t rc = fork();
if (rc == -1) LOGDEBUG("fork failed\n");
else if (rc == 0) ChildProcess();
else ParentProcess();
return 0;
}
void ChildProcess()
{
LOGDEBUG("Child process spawned.\n");
usleep(10 * 1000 * 1000);
LOGDEBUG("Child process exiting.\n");
}
void ParentProcess()
{
LOGDEBUG("Parent process spawned.\n");
usleep(5 * 1000 * 1000);
LOGDEBUG("Parent process exiting.\n");
}
输出:
16:10:28 SharedMemAccess( 59): Constructor
16:10:28 main( 25): In main
16:10:28 ParentProcess( 62): Parent process spawned.
16:10:28 ChildProcess( 47): Child process spawned.
16:10:33 ParentProcess( 72): Parent process exiting.
16:10:33 ~SharedMemAccess( 133): Destructor
16:10:38 ChildProcess( 57): Child process exiting.
16:10:38 ~SharedMemAccess( 133): Destructor
谢谢你,
-Joe
g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3. Edited for clarity.
I have a shared library in which I want to do something the first time it's loaded, and whenever there are no more references to it.
I have tried two ways to do it, with the same result. The first was using the suggestion at this link. The second was by creating a global instance of a class inside the library.
Each worked the same. I then built a test program that uses the library and fork()s off a process. It turns out the constructor only gets called once, but the destructor gets called twice - once for each process.
Is this the expected behavior for shared libs and fork(), or am I doing something wrong here? It seems very dangerous to have dtors called for each process and the ctor only called once.
Shared lib (g++ -fPIC -c -o myshare.o myshare.cpp / g++ -shared -o libmyshare.so myshare.o):
class SharedMemAccess
{
public:
SharedMemAccess();
~SharedMemAccess();
};
static SharedMemAccess g_sharedMem;
SharedMemAccess::SharedMemAccess()
{
LOGDEBUG("Constructor\n");return;
}
SharedMemAccess::~SharedMemAccess()
{
LOGDEBUG("Destructor\n");return;
}
Test driver (g++ -c -o main.o main.cpp / g++ main.o -lmyshare -o test):
int main()
{
LOGDEBUG("In main\n");
pid_t rc = fork();
if (rc == -1) LOGDEBUG("fork failed\n");
else if (rc == 0) ChildProcess();
else ParentProcess();
return 0;
}
void ChildProcess()
{
LOGDEBUG("Child process spawned.\n");
usleep(10 * 1000 * 1000);
LOGDEBUG("Child process exiting.\n");
}
void ParentProcess()
{
LOGDEBUG("Parent process spawned.\n");
usleep(5 * 1000 * 1000);
LOGDEBUG("Parent process exiting.\n");
}
Output:
16:10:28 SharedMemAccess( 59): Constructor
16:10:28 main( 25): In main
16:10:28 ParentProcess( 62): Parent process spawned.
16:10:28 ChildProcess( 47): Child process spawned.
16:10:33 ParentProcess( 72): Parent process exiting.
16:10:33 ~SharedMemAccess( 133): Destructor
16:10:38 ChildProcess( 57): Child process exiting.
16:10:38 ~SharedMemAccess( 133): Destructor
Thank you,
-Joe
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
那不是“共享内存”。您只是在一种非常弱化的意义上“共享”对象—— fork() 正在复制父进程已构造的对象,作为复制整个父进程的一部分。
作为大多数操作系统中的实现细节,您可以获得写时复制语义(因此将使用相同的物理内存位,直到一个进程尝试以某种方式改变页面),但一个进程的更改将在对方中不可见,并且从程序员的角度来看,对象的父对象实例与子对象的实例完全不同。 COW语义只是为了性能和效率优化。
您可以通过谷歌搜索来了解共享内存/对象的实际方法。 Beej 的 IPC 指南有一个很好的对一种形式的共享内存的介绍 。
然而,实际共享内存的语义不会与普通 C++ 对象构造/销毁的语义精确匹配。
That is not "shared memory". You are only "sharing" the objects in a very attenuated sense -- fork() is making a copy of the parent's already-constructed object as part of copying the entire parent process.
As an implementation detail in most operating systems, you get copy-on-write semantics (so the same physical bit of memory will be used until one process tries to mutate the page in some way), but the changes from one process will not be visible in the other, and from the programmer's perspective, the parent's instance of the object is completely distinct from the child's. COW semantics are just for performance and efficiency optimization.
You can read up on actual methods of sharing memory/objects with some googling. Beej's IPC guide has a nice introduction to one form of shared memory.
The semantics of actual shared memory will not precisely match the semantics of ordinary C++ object construction/destruction, however.
我意识到这是一个相当老的问题了,但是为了解决您原来的问题,您可以让析构函数查找进程的其他实例。如果多个进程仍在运行,那么您可能有活动引用,并且不应该清理共享内存。
您可以使用“pidof”获取指定进程的 PID 列表: pidof chrome
使用其他工具,您可以轻松确定有多少其他进程仍然处于活动状态。这对于通过管道发送到 sed 以创建逗号分隔的列表,然后用作 top 的输入以在重新启动后监视进程非常有用。
I realize that this is quite an old question by now but to address your original problem you could have your destructor look for other instances of your process. If multiple processes are still running then you probably have active references and shouldn't clean up the shared memory.
You can use "pidof" to get a list of PID's for a named process: pidof chrome
Using other tools you could easily determine how many other processes are still active. This is useful to pipe to sed to create a comma separated list and then use as input to top to monitor your processes after relaunching.