I am looking for some advice about OpenMP. I am confused about the use of threadprivate variables. The problem can be presented in the following example:
-----------
// The code below is located the dynamically loaded DLL.
/* Global variable. */
int *p;
#pragma omp threadprivate(p)
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)
{
p = malloc(sizeof(int));
*p = 0;
printf(“value = %d”,*p);
free(p);
}
-----------
Here I want each thread to have a separate copy of a global thread-independent variable that will be visible in all functions of the thread. The variable will be initialized and destroyed within the thread.
The “problem” here is that all code including definition of the global variable “p” is located the dynamically loaded DLL (via LoadLibrary).
Microsoft sayshttp://msdn.microsoft.com/en-us/library/2z1788dd.aspx: “You cannot use threadprivate in any DLL that will be loaded via LoadLibrary. This includes DLLs that are loaded with /DELAYLOAD (Delay Load Import), which also uses LoadLibrary.” So, if I got it right, the above code is not correct – threadprivate variables and dynamically loaded DLL do not mix.
To verify this I created a test project that dynamically loads a DLL add runs a function in parallel using threadprivate as described above. It all worked just fine!
Hmmm … Now I am confused because that project was not supposed to work.
Can I really use thread private variables in dinamic DLLs or is there a trick to this?
Thank you,
Alex
threadprivatein the MS OpenMP implementation is translated to__declspec(thread)which puts the declared variable in the static TLS (Thread-Local Storage). When a program is started the size of the TLS is determined by taking into account the TLS size required by the executable as well as the TLS requirements of all other implicitly loaded DLLs. When you load another DLL dynamically withLoadLibraryor unload it withFreeLibrary, the system has to examine all running threads and to enlarge or compact their TLS storage accordingly. According to KB118816:Access to such variables is considered undefined behaviour. It works in your case but it doesn’t mean that it will work everywhere and every time. Here you can read why exactly it would most likely fail on Windows XP/2003 and earlier Windows versions. According to the same source, implicit TLS handling was rewritten in Windows Vista and so OpenMP
threadprivateand__declspec(thread)should function correctly in run-time loaded DLLs since then. The proposed solution is to useTlsAllocinstead.dwTlsIdxshould be initialised on process attach inDllMainwith a call toTlsAlloc. Enough memory to hold anint *should be allocated on thread attach and its address should be set as the value of thedwTlsIdxTLS index. Or you could do it in on the first call toMyFunc2instead:See here for more details (with error checking).