开发者

Shared libraries, object constructors and fork() behavior

开发者 https://www.devze.com 2023-02-14 09:17 出处:网络
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.

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


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消