3

First off, there are some similar questions to this, but none really address the exact issue:

https://social.msdn.microsoft.com/forums/vstudio/en-US/b7701ee5-c9fa-4693-8ae1-d59736360514/question-about-static-variables-in-dll

http://cboard.cprogramming.com/cplusplus-programming/101543-global-static-variable-class-delivered-dll.html

So, here's my question: I'm working on a VST plugin, and I have a class that is defined and implemented within a DLL. Multiple instances of this same DLL are loaded, and what I'd like to do is maintain an "instance count" that monitors how many times the class is constructed (which only occurs once, when the DLL is loaded per the VST standard.)

One straightforward way of doing this would be to create a class static variable that I initialize to 0 and increment in the constructor / decrement in the destructor. I'm confident that I know when my class is constructed and destructed, but what I'm unsure of is whether or not this class static variable will be shared across instances of my DLL.

To clarify, I am loading the same DLL multiple times; within the DLL is a class (used only within the DLL code, and not exposed to the application.) There is some discussion on whether or not the behavior of data defined in DLLs varies between Windows and Unix, so I'd like to know if doing this kind of thing within a DLL is safe for cross platform use.

An example class, defined within the DLL, and not exposed in any way to the application loading the DLL (or otherwise.)

Header File

// Foo.h
# pragma once
class Foo {
    static int s_InstanceCount;
public:
    Foo();
    ~Foo();
};

And now the source file

// Foo.cpp
#include "Foo.h"
int Foo::s_InstanceCount = 0;

Foo::Foo() {
    s_InstanceCount++;
}

Foo::~Foo() {
    s_InstanceCount--;
    if (s_InstanceCount == 0) {
        // Do something
    }
}

The constructor of Foo is only called when the DLL is loaded by an application (i.e ::LoadLibrary on Windows), and the destructor is only called when the DLL is freed (i.e ::FreeLibrary on Windows). Consider that guaranteed. Will s_InstanceCount be shared across calls to the Constructor?

EDIT: As Serge points out below, a process can't really load a DLL twice. So, when my DLL is loaded twice by one process, the Foo instances that get constructed exist within the same memory space used by the loading process. Maybe...

John Joseph
  • 115
  • 2
  • 6
  • 1
    Of course, instanceCount should be `atomic`. – Billy ONeal Nov 03 '15 at 16:04
  • Right, in practice I have a critical section but I wanted a simple example. – John Joseph Nov 03 '15 at 16:24
  • No, in practice you want `atomic`, not `CRITICAL_SECTION`, for this. `CRTICAL_SECTION`s only work within a process, not cross process. – Billy ONeal Nov 03 '15 at 16:25
  • See Serge's comment. This is the same process "reloading" the same DLL, which isn't really a thing, so when the DLL is "reloaded" I'm really just accessing the same variables. So really my question is poorly phrased, because it is impossible for a process to reload a DLL. But, if multiple ::LoadLibrary calls are made on the same DLL, then the variables accessed in that DLL will be shared across class instances(I think.) – John Joseph Nov 03 '15 at 16:57
  • You should still use `atomic`. – Billy ONeal Nov 03 '15 at 21:05

2 Answers2

5

The DLL is just shared code that is run in the address space of the processes calling it. Every process gets its own copy of the global/static variables defined in the DLL.

This article explains this to you. But it also gives a nice workaround to share data accross several processes using a file mapping. This should help you solve your issue.

Edit: There is apparently another solution, creating a shared data segment (i.e. tell the linker to share some of the data, like it does for the code). Here microsoft doc and and a proof of concept on codeproject. I have never used it, so it remains to be tested if it works for static class members as well.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Thanks! I need some more characters. – John Joseph Nov 03 '15 at 16:23
  • PS: in th meantime I've experimented with the shared segment approach. While I could get it to work with a global or a static variable, I couldn't manage to get static class member variables shared. – Christophe Nov 03 '15 at 17:31
  • Shared data segments are a legacy technology, and should be avoided because they [are insecure](http://blogs.msdn.com/b/oldnewthing/archive/2004/08/04/208003.aspx). – Harry Johnston Nov 03 '15 at 23:05
  • @HarryJohnston interesting. Another restriction seems to be the use of simple data only, because dynamic objects would necessarily allocate memory outside the shared segment and cause undefined behaviour by pointing to non-shared memory. – Christophe Nov 03 '15 at 23:13
1

No, s_InstanceCount in your example will be private to each instance of the DLL. Furthermore, without tweaking the file name of the DLL you normally can't load it multiple times in the same process, as explained here: Load the same dll multiple times . If the DLL instances are in different processes in your case, then you need inter-process communication e.g. via shared memory .

Community
  • 1
  • 1
Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
  • Hmmm. So what I imagine is really happening is every time the DLL is "reloaded" is that nothing happens; the same variables inside the same DLL are being accessed by the same process. Which is what I want. Thanks! – John Joseph Nov 03 '15 at 16:51
  • How do you know that the DLL is "reloaded"? I can't imagine how what you describe can happen: when a DLL is unloaded, the variables belonging to it should be destroyed, so new load of the DLL should get new variables. – Serge Rogatch Nov 04 '15 at 06:36
  • What if it's loaded twice before ever being unloaded? To expand, a VST3 plugin is a DLL that gets loaded by a digital audio workstation (VST3 host) and gets treated as an instrument or an effect; you can have multiple instances of the same plugin, and it's up to the host to decide how they manage that. This is the situation I'm dealing with, where there are multiple instances of the same plugin, which "share" the same loaded DLL. – John Joseph Nov 04 '15 at 16:39
  • @JohnJoseph, do you mean the DLL loaded multiple times in the same process or in different processes? – Serge Rogatch Nov 05 '15 at 05:18