Consider the following snippet:
#include <map>
class A {
static std::map<int,int> theMap;
#pragma omp threadprivate(theMap)
};
std::map<int,int> A::theMap;
Compilation with OpenMP fails with the following error message:
$ g++ -fopenmp -c main.cpp
main.cpp:5:34: error: ‘threadprivate’ ‘A::theMap’ has incomplete type
I don’t understand this. I can compile without the #pragma directive, which should mean that std::map is not incomplete. I can also compile if theMap is a primitive type (double, int…).
How do I make a global static std::map threadprivate?
This is a compiler restriction. Intel C/C++ compiler supports C++ classes on
threadprivatewhile gcc and MSVC currently cannot.For example, in MSVC (VS 2010), you will get this error (I removed the class):
So, the workaround is pretty obvious, but dirty. You need to make a very simple thread-local storage. A simple approach would be:
Note that the reason why I have padding is to avoid false sharing. I assume that 64-byte cache line for modern Intel x86 processors.
__declspec(align(64))is a MSVC extension that the structure is on the boundary of 64. So, any elements intlswill be located on a different cache line, resulting in no false sharing. GCC has__attribute__ ((aligned(64))).In order to access this simple TLS, you can do this:
tls[omp_get_thread_num()].theMap;Of course, you should call this inside one of OpenMP parallel constructs. The nice thing is that OpenMP provides an abstracted thread ID in [0, N), where N is the maximum thread number. This enables a fast and simple TLS implementation. In general, a native TID from operating system is an arbitrary integer number. So, you mostly need to have a hash table whose access time is longer than a simple array.