请考虑以下代码段:
#include <map>
class A {
static std::map<int,int> theMap;
#pragma omp threadprivate(theMap)
};
std::map<int,int> A::theMap;
Run Code Online (Sandbox Code Playgroud)
使用OpenMP进行编译失败,并显示以下错误消息:
$ g++ -fopenmp -c main.cpp
main.cpp:5:34: error: ‘threadprivate’ ‘A::theMap’ has incomplete type
Run Code Online (Sandbox Code Playgroud)
我不明白这一点.我可以编译没有#pragma指令,它应该意味着std::map是不完整的.如果Map是基本类型(double,int ...),我也可以编译.
如何制作全局静态std::map threadprivate?
这是编译器的限制。英特尔 C/C++ 编译器支持 C++ 类,threadprivate而 gcc 和 MSVC 目前不支持。
例如,在MSVC(VS 2010)中,您将收到此错误(我删除了该类):
static std::map<int,int> theMap;
#pragma omp threadprivate(theMap)
error C3057: 'theMap' : dynamic initialization of 'threadprivate' symbols is not currently supported
Run Code Online (Sandbox Code Playgroud)
因此,解决方法非常明显,但很脏。您需要制作一个非常简单的线程本地存储。一个简单的方法是:
const static int MAX_THREAD = 64;
struct MY_TLS_ITEM
{
std::map<int,int> theMap;
char padding[64 - sizeof(theMap)];
};
__declspec(align(64)) MY_TLS_ITEM tls[MAX_THREAD];
Run Code Online (Sandbox Code Playgroud)
请注意,我之所以有填充是为了避免错误共享。我假设现代 Intel x86 处理器有 64 字节缓存线。__declspec(align(64))是一个 MSVC 扩展,该结构位于 64 的边界上。因此,其中的任何元素都tls将位于不同的缓存行上,从而不会出现错误共享。海湾合作委员会有__attribute__ ((aligned(64))).
为了访问这个简单的 TLS,您可以执行以下操作:
tls[omp_get_thread_num()].theMap;
当然,您应该在 OpenMP 并行构造之一内调用它。好处是 OpenMP 在 [0, N) 中提供了一个抽象的线程 ID,其中 N 是最大线程数。这可以实现快速、简单的 TLS 实施。一般来说,操作系统的本机 TID 是任意整数。因此,您通常需要一个访问时间比简单数组长的哈希表。
| 归档时间: |
|
| 查看次数: |
2113 次 |
| 最近记录: |