Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible for multiple Dynamic Link Libraries (DLL) to share Thread Local Storage from a Static Library (LIB)

I have a game made up of many DLL files. Some of these DLLs link to the same static library (LIB).

So something like this:

Game.exe -> Root.dll -> Child.dll
               |            |
               |            '-> Common.lib (contains __declspec(thread))
               |
               '-> Common.lib (contains __declspec(thread))

Root.dll loads Child.dll which statically links Common.lib. Root also statically links Common.lib. Because Common is statically linked, it gets compiled directly into the loading dll (eg. Root and Child).

Common.lib contains a variable using Thread Local Storage (TLS).

__declspec(thread) static void* s_threadValues[PlatformThreadSlotsMax];

This results in some problematic behavior: Root.dll and Child.dll each contain a different instance of the TLS data (s_threadValues). Even on the same thread, if Root.dll calls a function defined in Common.lib, the value of s_threadValues will be different from its value if that same function is called from Child.dll.

Since both DLL are accessing this TLS from the same thread, I would expect the TLS to be shared, but it is not.

Now, if I change Common.lib to a dynamically link (eg. Common.dll) this issue does not occur anymore: s_threadValues is the same for both Root.dll and Child.dll.

Is this expected behavior? Is there anyway to have the TLS shared defined in the static lib shared between dynamic libs using it?

like image 978
Goose Avatar asked Jan 03 '14 21:01

Goose


1 Answers

This is entirely normal. Each DLL has its own copy of the library code and data. And its own thread-local state.

You can reason this out by assuming it would work the way you expected. Then two DLLs could accidentally have their own thread-local variables shared between different DLLs. Clearly that would be disastrous. It can't work that way because there is no mechanism to share the TLS instance across modules. The slot indices are intentionally kept private to the module, there's no mechanism to obtain the slot index of a __declspec(thread) variable. Calling TlsAlloc() explicitly and sharing the index would be a workaround. Don't go there.

like image 90
Hans Passant Avatar answered Oct 23 '22 00:10

Hans Passant