0
4

3 回答 3

1

threadprivate在 MS OpenMP 实现中被转换为__declspec(thread)将声明的变量放入静态 TLS(线程本地存储)中。当程序启动时,TLS 的大小是通过考虑可执行文件所需的 TLS 大小以及所有其他隐式加载的 DLL 的 TLS 要求来确定的。当您使用 动态加载LoadLibrary或卸载另一个 DLL 时FreeLibrary,系统必须检查所有正在运行的线程并相应地扩大或压缩它们的 TLS 存储。根据KB118816

这个过程对于操作系统来说管理太多,当动态加载 DLL 或代码引用数据时,这可能会导致异常。

访问这些变量被认为是未定义的行为。它适用于您的情况,但这并不意味着它可以随时随地使用。在这里,您可以了解为什么它在 Windows XP/2003 和更早的 Windows 版本上很可能会失败。根据同一来源,隐式 TLS 处理在 Windows Vista 和 OpenMP 中被重写,并且threadprivate从那时__declspec(thread)起应该在运行时加载的 DLL 中正确运行。建议的解决方案是改为使用TlsAlloc

DWORD dwTlsIdx;

extern "C" __declspec(dllexport) int MyFunc1(void)
{
   int i;
   #pragma omp parallel for
   for (i = 0; i < n; i++) {
      MyFunc2(i);
   }
   return TRUE;
}

void MyFunc2(void)
{
    int **pp = (int **)TlsGetValue(dwTlsIdx);
    *pp = malloc(sizeof(int));
    **pp  = 0;
    printf(“value = %d”,**pp);
    free(*pp);
}

dwTlsIdx应通过DllMain调用TlsAlloc. 应该在线程附加上分配足够的内存来保存一个int *,并且它的地址应该设置为dwTlsIdxTLS 索引的值。或者你可以在第一次调用时这样做MyFunc2

void MyFunc2(void)
{
    int **pp = (int **)TlsGetValue(dwTlsIdx);
    if (pp == NULL)
    {
       pp = malloc(sizeof(int *));
       TlsSetValue(dwTlsIdx, pp);
    }
    *pp = malloc(sizeof(int));
    **pp  = 0;
    printf(“value = %d”,**pp);
    free(*pp);
}

有关更多详细信息,请参见此处(带有错误检查)。

于 2012-10-02T11:03:09.513 回答
0

我没有尝试使用 OMP,但我有很好的使用经验

DWORD WINAPI TlsAlloc(void);

和其他TlsXxx功能。我很确定这threadprivate(p)是最终实现此功能的包装器。此功能在 exe、静态和动态加载的 dll 等中完美运行。

在一种情况下,我在处理过程中同时看到了大约 800 个 TLS 索引。每个线程(大约 200 个线程)在其线程本地存储中都有这个数量的对象。NT 在堆中分配缓冲区来处理这些数据。所有这一切都很好。

可能是在写 MSDN 文章的时候出现了一些问题,但现在很可能已经修复了。

我的 2 美分。

于 2012-10-02T04:02:36.483 回答
0

赫里斯托和基里尔,

感谢您的回复。

微软似乎已经解决了动态 DLL 中的 TLS 问题(至少在我使用的 Windows 7 中)。也许他们只是没有更新文档。我保持手指交叉。

我创建了一个测试项目,在其中通过 __declspec(thread) pragmas 使用 TLS 测试了这个想法(正如 Hristo Iliev 在另一篇文章中向我建议的那样)。该项目使用了大量的 TLS 变量(只是为了测试)并且一切正常。然后我在工作项目中移动了代码。这是一个加载许多动态 DLL 的大型项目(约 100 万行代码)。这一切也都在那里工作。

对于最坏的情况,我仍然持有使用 TlsAlloc、TlsSetValue、TlsGetValue 函数的想法。但它并不适合我,因为我担心这些功能会在我拥有的数字运算代码中增加大量偷听。我的库只需要一些 TLS 变量,但这些变量在代码中被广泛使用,包括位于堆栈深处的低级函数。

干杯,

亚历克斯·亚姆奇科夫

于 2012-10-03T01:31:34.587 回答