C++ – Global variable in a Linux shared library

c

Suppose we have the following setup under Linux, .so library named "libcnt.so" and 3 user space apps: "app1", "app2", "app3". This library does 1 simple thing, it says to the app (app dynamically links the library at runtime) by how many apps it is already linked. Apps should have access to link counter. My knowledge in C and Linux is somewhat limited in this aspect, but as I understand this information should be stored in a global variable inside the shared object. Something like:

in libcnt.h
extern int cnt_loads;

in libcnt.c
int cnt_loads = 0; // where each linking increments this counter

or something…

So, my question is how it should be declared and/or defined inside .so library to guaranty that multiple apps from user space get the same instance of that variable counter?

Best Answer

In general, mutable memory location will not be shared between applications unless explicitly asked for. Thus, when libcnt writes to cnt_loads, the page on which cnt_loads resides on will be duplicated. This behaviour is known as copy-on-write (COW). The same thing happens if you duplicated a process with fork(): the child process will not share writeable memory with the parent, if any write occurs to "forked" page, the page will be duplicated.

If you want to use shared memory for interprocess communication, you should use SystemV shared memory, POSIX shared memory or mmap instead. Note that these methods are somewhat persistent, i.e. you will need to remove the shared memory object after use.

You can approximate the behaviour you originally wanted using shared memory by defining __attribute__((constructor)) and __attribute__((destructor)) functions for your shared library. The constructor function is run every time the library is opened, so you can use it to initialize/open the shared memory and increment the the load count. If you also maintain a reference count (how many times the shared library is open in the system right now) with the destructor---in addition to the load count---, your can properly remove the shared memory once the reference count falls to 0.

Note that using shared memory for inter-process communication absolutely requires some form of mutual exclusion, for example a semaphore or mutex. Failing to synchronize properly will lead to race conditions (for example, what happens when two processes open your library at precisely same time?). You may avoid mutual exclusion if you can increment/decrement the counters in an atomic way. I recommend you to use OS provided inter-process semaphores instead of atomics, because atomic operations are tricky to utilize properly, and your problem is not performance critial at all (thus no need for lock-free operations).

Related Topic