请考虑以下代码段:
#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
不不完整。如果Map是基本类型(double,int ...),我也可以编译。
如何制作全局静态std::map
threadprivate
?
答案 0 :(得分:2)
这是编译器限制。英特尔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
中的任何元素都将位于不同的缓存行上,从而不会产生错误共享。海湾合作委员会有__attribute__ ((aligned(64)))
。
要访问这个简单的TLS,您可以这样做:
tls[omp_get_thread_num()].theMap;
当然,你应该在一个OpenMP并行结构中调用它。好处是OpenMP在[0,N)中提供了抽象的线程ID,其中N是最大线程数。这样可以实现快速简单的TLS实现。通常,来自操作系统的本机TID是任意整数。因此,您通常需要一个哈希表,其访问时间比简单数组长。
答案 1 :(得分:1)
不完整类型错误是编译器中的错误,可以通过在threadprivate指令之前实例化std::map<int,int>
来解决。但是一旦你解决了这个问题,GCC 4.7仍然不支持threadprivate变量的动态初始化。这将在GCC 4.8中得到支持。
答案 2 :(得分:0)
将为每个线程复制任何threadprivate。我通过创建一个静态对象(类不需要是静态的,只是实例化的对象必须是静态的)来完成这个。也许这就是你想要的?
现在考虑是否希望在线程之间共享类的某些成员。只使类的某些成员静态意味着如果每个线程实例化该对象,那么我们应该仅复制静态部分(因为它的threadprivate)而不是整个对象(不复制共享内存)。这将需要一个对象使所有内容和所有其他对象具有更小的尺寸(不重新存储共享内存),但仍然具有对共享内存的引用,这很坦率地说没有意义。
作为建议,请自己创建两个类,一个是严格(线程)私有数据,另一个是共享数据。