考虑以下片段:
#include <map>
class A {
static std::map<int,int> theMap;
#pragma omp threadprivate(theMap)
};
std::map<int,int> A::theMap;
使用 OpenMP 编译失败并显示以下错误消息:
$ g++ -fopenmp -c main.cpp
main.cpp:5:34: error: ‘threadprivate’ ‘A::theMap’ has incomplete type
我不明白这个。我可以在没有 #pragma
指令的情况下进行编译,这应该意味着 std::map
不是不完整。如果 theMap 是原始类型(double、int...),我也可以编译。
如何创建全局静态 std::map
threadprivate
?
最佳答案
这是一个编译器限制。英特尔 C/C++ 编译器支持 threadprivate
上的 C++ 类,而 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
所以,解决方法很明显,但是很脏。您需要制作一个非常简单的线程本地存储。一个简单的方法是:
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];
请注意,我有填充的原因是为了避免 false sharing .我假设现代 Intel x86 处理器的 64 字节高速缓存行。 __declspec(align(64))
是一个 MSVC 扩展,该结构位于 64 的边界上。因此,tls
中的任何元素都将位于不同的缓存行上,导致没有虚假共享。 GCC 具有 __attribute__ ((aligned(64)))
。
为了访问这个简单的 TLS,您可以这样做:
tls[omp_get_thread_num()].theMap;
当然,您应该在 OpenMP 并行结构之一中调用它。好消息是 OpenMP 在 [0, N) 中提供了一个抽象的线程 ID,其中 N 是最大线程数。这可以实现快速简单的 TLS 实现。通常,来自操作系统的 native TID 是任意整数。因此,您最需要的是一个哈希表,其访问时间比简单数组长。
关于c++ - 在 C++ STL 类型的静态实例上使用 OpenMP threadprivate 指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8051108/