6

I have a multithreaded application. I declare a class with a static member in a shared library.

Printing the address of the member from different threads from different libraries shows different results.

//declaration

template <class OBJECT>
struct Container
{
   static int m_member;
};

template <class OBJECT>
int Container<OBJECT>::m_member;

// printing

cout << (void*) &Container<int>::m_member << endl;

How could that be?

Ezra
  • 1,401
  • 5
  • 15
  • 33
  • When you say different threads from different libraries you mean you have one process that has several threads that access the the member? When I remember correctly, I heard that shared libraries are instantiated per process, so each process has its own version (to not interfere with other processes). – Nobody moving away from SE Jul 26 '12 at 09:26
  • 1
    How do you link the "shared library"? – Kerrek SB Jul 26 '12 at 09:26
  • It is one process with several threads. The member is defined in the header file (In my real code Container is templated) but I'm quite sure that this is not the problem. – Ezra Jul 26 '12 at 09:28
  • @Ezra: Why are you quite sure that this is not the problem. With `Container` not being a template you risk violating ODR if the definition of `Container::m_member` is included in more than one translation unit. – CB Bailey Jul 26 '12 at 09:36
  • @CharlesBailey Container is template, I'll change the code in the question accordingly. – Ezra Jul 26 '12 at 09:38

1 Answers1

6

If you have different libraries, (I'm guessing different dynamic libraries), then you may have some duplication of both code and static variables.

The exact details will depend on the particular dynamic library technology you are using. I'd say that, for example, in Windows DLLs you will have duplicated code and variables, but in Linux SOs you will not.

Anyway, you should give more details on the Operating System and the layout of your project.

UPDATE: Ahh, but your class is a template! Template instantiations in a shared library are a strange beast! To make sure that only one copy of your class is used across all the process you have to explicitly instantiate the template and make sure that this instantiation is exported in the SO, and that it is used from the client code. The details vary with the compiler, but you can check how the std::string is done, for example:

In the header file:

namespace std
{
    extern template class basic_string<wchar_t>;
}

In the source of the library:

namespace std
{
    template class basic_string<wchar_t>;
}

Naturally you need to know in advance which instantiations will be needed of your template. Obviously, the SO cannot export an instantiation that uses a type it knows nothing about.

UPDATE: Ahh, but you have two different libraries instantating the template... then if both libraries define the explicit instantiation as extern the shared ELF magic should merge both instantiations into one.

YET ANOTHER UPDATE: After playing with templates and shared objects, it usually just works. My guess now is that you are compiling the libraries with -fvisibility=hidden or similar. If that is the case, it would be enough just to write:

template <class OBJECT>
struct __attribute__((visibility("default"))) Container
{
   static int m_member;
};

To make the specializations of the template to enter the dynamic symbol table, and thus avoid the duplication.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • I use linux CentOS, therefore SO. As far as I know, there should be only one instance of Container::m_member. – Ezra Jul 26 '12 at 09:33
  • +1. However, I've tried your suggestions and still getting two instances. If that could give a hint: the addresses I'm seeing are of different lengths: 0x61bdb0, 0x2aaaab92d5b0. My machine is 64bit. – Ezra Jul 26 '12 at 21:34
  • @Ezra: I've done an example and was able to get both results (same address or different addresses) just playing with the visibility options. You really should post some compilable code and the compiler commands that reproduce your problem. – rodrigo Jul 26 '12 at 22:41
  • I cannot reduce my code to a compiling example, it's a huge codebase. When I try to build this scenario from scratch the problem does not reproduce and I always get one instance of my static. However, I do not use -fvisibility, though I tried to add it according to your suggestion but then the code does not compile (many undefined references). I am going to bypass my problem by making my static a singleton. Many thanks! – Ezra Jul 28 '12 at 06:48