共享库,对象构造函数和fork()行为

时间:2011-03-01 21:29:23

标签: c++ linux fork shared

g ++(Ubuntu 4.4.3-4ubuntu5)4.4.3。编辑清晰。

我有一个共享库,我想在第一次加载时执行某些操作,并且只要没有更多引用就可以了。

我尝试了两种方法,结果相同。第一个是using the suggestion at this link。第二种方法是在库中创建一个类的全局实例。

每个都是一样的。然后我构建了一个测试程序,该程序使用库和fork()关闭进程。事实证明,构造函数只被调用一次,但析构函数被调用两次 - 每次进程调用一次。

这是共享库和fork()的预期行为,还是我在这里做错了什么?让dtors调用每个进程并且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

2 个答案:

答案 0 :(得分:5)

那不是“共享内存”。你只是在非常衰减的意义上“共享”对象 - fork()正在复制父已经构造的对象,作为复制整个父进程的一部分。

作为大多数操作系统中的实现细节,您将获得写时复制语义(因此在一个进程尝试以某种方式改变页面之前将使用相同的内存物理位),但是来自一个进程的更改将在另一个中可见,并且从程序员的角度来看,父对象的实例与孩子的实例完全不同。 COW语义仅用于性能和效率优化。

您可以通过一些Google搜索来了解共享内存/对象的实际方法。 Beej的IPC指南有一个很好的introduction to one form of shared memory

然而,实际共享内存的语义 not 与普通C ++对象构造/销毁的语义完全匹配。

答案 1 :(得分:0)

我意识到这是一个相当古老的问题但是为了解决您的原始问题,您可以让析构函数查找您的进程的其他实例。如果多个进程仍在运行,那么您可能有活动引用,不应该清理共享内存。

您可以使用“pidof”获取指定流程的PID列表:pidof chrome

使用其他工具,您可以轻松确定还有多少其他进程仍处于活动状态。这对于管道sed创建逗号分隔列表然后用作top的输入以在重新启动后监视您的进程非常有用。