【发布时间】:2014-01-03 21:59:51
【问题描述】:
我有一个由许多 DLL 文件组成的游戏。其中一些 DLL 链接到同一个静态库 (LIB)。
所以是这样的:
Game.exe -> Root.dll -> Child.dll
| |
| '-> Common.lib (contains __declspec(thread))
|
'-> Common.lib (contains __declspec(thread))
Root.dll 加载静态链接 Common.lib 的 Child.dll。 Root 也静态链接 Common.lib。因为 Common 是静态链接的,所以它直接编译到加载的 dll 中(例如 Root 和 Child)。
Common.lib 包含一个使用线程本地存储 (TLS) 的变量。
__declspec(thread) static void* s_threadValues[PlatformThreadSlotsMax];
这会导致一些有问题的行为:Root.dll 和 Child.dll 都包含一个 不同 的 TLS 数据实例 (s_threadValues)。即使在同一个线程上,如果 Root.dll 调用 Common.lib 中定义的函数,则 s_threadValues 的值将与从 Child.dll 调用相同的函数时的值不同。
由于两个 DLL 都从同一个线程访问此 TLS,我希望 TLS 是共享的,但事实并非如此。
现在,如果我将 Common.lib 更改为动态链接(例如 Common.dll),则此问题不会不再发生:对于 Root.dll 和 Child.dll,s_threadValues 是相同的。
这是预期的行为吗?无论如何在使用它的动态库之间共享静态库中定义的 TLS 共享?
【问题讨论】:
-
单身人士在这里很有用,但如果你想让你的班级保持静态,那就不能很好地工作(你必须为你的单身人士公开一个 setter - 它很hacky但它有效)。不过,我希望有更好的解决方案。
-
AFAIK,预期行为:“全局”变量仅对模块是全局的(在 Windows 意义上)。要在模块之间共享一个,您必须将其存储在单个模块中并让其他人调用它,或者找到另一种存储(我个人使用基于 processID 名称的文件映射)
-
@Warty 您是说,与其将 s_threadValues 作为全局变量,不如将其作为 Singleton 的成员(而不是 TLS 值)?在这样做时,它最终不会在线程之间共享(它首先试图避免这种情况)吗?
-
静态库完全不相关。它们不以任何形式或形式存在于可执行程序中。它们只是目标文件的容器。您最好永远不要创建任何静态库并直接使用目标文件。
-
1.是的。 2. 让我再试一次。可执行代码中没有静态库。它们只是目标文件的容器,而目标文件只是目标代码的容器。链接器使用该目标代码来构建模块(.dll 和 .exe 文件)。您也可以直接使用目标文件,而无需创建静态库,并构建完全相同的模块。这就是为什么您使用静态库这一事实无关紧要。重要的是您是否在一个模块中有一个变量副本,或者在两个模块中有两个这样的副本。
标签: c++ multithreading dll static-libraries thread-local-storage