__declspec(thread)变量是在静态链接的时候确定存储位置的, 如果动态加载, 这些变量实际上都是空, 地址可能是0或者任何数值.
MSDN的说明: 在 Windows Vista 之前的 Windows 操作系统中,__declspec( thread ) 有一些限制。 如果 DLL 将任何数据或对象声明为 __declspec(线程),则动态加载该 DLL 时会导致保护错误。 使用 LoadLibrary 加载 DLL 后,每当代码引用 __declspec(线程)数据时,该 DLL 都将导致系统故障。 由于线程的全局变量空间是在运行时分配的,因此此空间的大小是以应用程序的需求和所有静态链接的 DLL 的需求相加为基础计算出来的(也就是说,DLL所需的存储空间实际上仍然是引用它的进程来分配的,所以同一个DLL被不同的进程引用各自都有独立的地址空间,而存在线程变量的空间是编译EXE时确定的,所以LoadLibrary的DLL,因为只有EXE运行的时候才执行,编译时是无法确定的。但是Vista之后的版本,使用了其它机制,保证动态加载DLL,这些线程变量仍然能够正确的获得所需空间)。 使用 LoadLibrary 时,无法扩展此空间以允许放置用 __declspec( thread ) 声明的线程本地变量。 如果 DLL 可能是用 LoadLibrary 加载的,请在 DLL 中使用 TLS API(如 TlsAlloc)来分配 TLS。
TLS有4个函数: TlsAlloc(), TlsFree(index), TlsSetValue(index,value), TlsGetValue(index).
但是仍然有问题, 使用一个线程变量需要一个数字索引, 这个数字索引存储在哪里呢? 一个办法是, 声明几个全局的静态整数, 分别存储索引, 需要操作某个线程变量, 就从对应的静态整数取索引, 然后在使用索引操作线程变量.