1

I'm trying to use a singleton in a DLL to globally configure logging. While everything works fine with one EXE using the DLL, when another EXE uses the same DLL at the same time, they seem to share the singleton (i.e. memory location and value of singleton and m_verbose are identical in both processes).

Shouldn't the DLL data memory be separate for the different processes? How could I get the singleton not to share the variable m_verbose in particular?

I'm on Windows using MSVC. This is my singleton code in the header:


#if COMPILING_DLL
    #define DLLEXPORT __declspec(dllexport)
#else
    #define DLLEXPORT __declspec(dllimport)
#endif

struct LogVerbose
{
    static LogVerbose& instance()
    {
        static LogVerbose logVerbose;
        return logVerbose;
    }

    LogVerbose(const LogVerbose&) = delete;
    LogVerbose& operator = (const LogVerbose&) = delete;

    static COMPILING_DLL bool isVerbose();
    static COMPILING_DLL void setVerbose(bool verbose = true);

private:
    LogVerbose() : m_verbose(false) {}
    ~LogVerbose() {}

    bool m_verbose;
};

isVerbose and setVerbose are defined in the .cpp file but are mere accessors.

Thanks for any help.

Alex H
  • 190
  • 1
  • 9
  • It's reasonable for the memory location (by which I assume you mean address) to be the same, but are you sure about the value? – Paul Sanders Aug 25 '23 at 13:20
  • You do know singletons have their issues don't you? How are and when are you planning to initialize and destruct your instance? (e.g. have you designed its lifetime?). Before you commit to this at least investigate abstract baseclasses (interfaces) and dependency injection. (it will also increase the unit testability of your code). – Pepijn Kramer Aug 25 '23 at 13:21
  • The advise I have on design is : Declare abstract baseclasses with methods like "ReportXYZHappened" and use this in your business logic. (e.g. NO log statements at all). Then you can make logging adapters implementing those methods and make real log messages out of them. This means that duing unit testing you can inject mocks/stubs in your code that either do nothing, or count the number of times they are called so you can verify logging will take place in production without having to setup any actual logging during unit testing. – Pepijn Kramer Aug 25 '23 at 13:24
  • 1
    Generally, DLLs have memory and data that are created uniquely for each calling process. In fact, it can be quite tricky to get a DLL to share its memory/resources across processes. As @PepijnKramer says - are you *sure* your two EXEs are using the same instance of the DLL? – Adrian Mole Aug 25 '23 at 13:24
  • With my advice you can also have logging implementations that use RPC calls to a single logging server which then will handle all the log configuration in a single log process. – Pepijn Kramer Aug 25 '23 at 13:26
  • ... See, for example: https://stackoverflow.com/q/17700409/10871073 – Adrian Mole Aug 25 '23 at 13:27
  • Problem is that yo assume each process uses unique address space. It used to be like this, now on modern hardware system can control where each process see specific fragment of memory. As result processes can use same address space but see different memory. There is no such think like unique address for process. It is even possible to see same memory at different address (for different processes or on single process). – Marek R Aug 25 '23 at 13:50
  • I recalled in windows, all the dll are built with `-fPIC` ish flags. That is, they don't share memory for between processes. – Louis Go Aug 25 '23 at 13:55

1 Answers1

1

In most modern OSes, every process has a unique virtual memory map. In Windows, DLLs have a preferred "base address" to which they are loaded in every process' virtual memory. This allows the OS to load the DLL into physical memory once and give every process its own memory mapping to that DLL.

DLLs normally have a code section that is read-only and a section for global variables that is read-write. The read-only section is shared between processes (unless there is a conflict in base addresses and your DLL needs to be relocated), but the global variables section is private to every process that loads the DLL.

In other words, unless you use very non-standard techniques it is impossible for the state of m_verbose and other variables to be shared between processes.

Botje
  • 26,269
  • 3
  • 31
  • 41
  • OK. You're all right, and I probably should have checked more thoroughly beforehand. While the shown memory location is the same in all cases, the value is not and it's not shared. Thanks to all for your explanations. – Alex H Aug 25 '23 at 14:09
  • @AlexH different processes can have the same *virtual* memory addresses assigned to them, but have different datas stored at those addresses. – Remy Lebeau Aug 25 '23 at 18:30