JNI多线程调用DLL全局变量处理,TLS实现
2017-06-22 00:00
369 查看
摘要: JNI多线程调用DLL全局变量处理,TLS实现,线程间全局变量互不干扰
最近公司项目用到C/C++的跨平台调用,因为调用方是JAVA,所以调用方式选择了JNI,但是在实现过程中遇到了颇多问题。今天就说一说其中一个,DLL多线程全局变量互相干扰的问题。
JAVA的业务需要在调用过程中采用多线程的方式,因为C实现算法中用到了很多全局静态变量,JNI在调用的时候就不可避免的出现各个线程间的全局变量互相干扰的问题。然后各种查找解决方案。
最初是想在不改DLL的前提下解决,尝试的是通过java掉命令的方式,在多个进程中调用dll,问题肯定是可以解决的
,但是综合考虑系统资源开销太大。PASS
最后决定修改DLL,敲定的解决方案是使用TLS方式存储用到的全局变量。各种查询,发现了C/C++解决全局变量多线程调用互相干扰的问题很简单的方式,就是在用到的全局变量前都加上__declspec(thread)来修饰就可以了(例如:__declspec(thread) int index;)。看起来确实很简单,开始修改DLL并调用调试,但是结果却不是跟预想中的一样!!!继续谷哥、度娘,http://blog.csdn.net/pgmsoul/article/details/8580415,看到了这位仁兄的这篇文章,豁然开朗。原来__declspec(thread)这种方式在动态连接库中调用是不行的,需要自己去实现TLS存储。好吧,还是去找权威吧https://msdn.microsoft.com/en-us/library/ms686997(v=vs.85).aspx,这里写的很详细了。根据微软说明,简单封装了一下需要用到的函数,调试通过,问题解决了。
下载调试过程中的DLL源码,请移步至 http://download.csdn.net/detail/bingge1022/9870979
Tls.cpp源码
取值\赋值调用关键代码
最近公司项目用到C/C++的跨平台调用,因为调用方是JAVA,所以调用方式选择了JNI,但是在实现过程中遇到了颇多问题。今天就说一说其中一个,DLL多线程全局变量互相干扰的问题。
JAVA的业务需要在调用过程中采用多线程的方式,因为C实现算法中用到了很多全局静态变量,JNI在调用的时候就不可避免的出现各个线程间的全局变量互相干扰的问题。然后各种查找解决方案。
最初是想在不改DLL的前提下解决,尝试的是通过java掉命令的方式,在多个进程中调用dll,问题肯定是可以解决的
,但是综合考虑系统资源开销太大。PASS
最后决定修改DLL,敲定的解决方案是使用TLS方式存储用到的全局变量。各种查询,发现了C/C++解决全局变量多线程调用互相干扰的问题很简单的方式,就是在用到的全局变量前都加上__declspec(thread)来修饰就可以了(例如:__declspec(thread) int index;)。看起来确实很简单,开始修改DLL并调用调试,但是结果却不是跟预想中的一样!!!继续谷哥、度娘,http://blog.csdn.net/pgmsoul/article/details/8580415,看到了这位仁兄的这篇文章,豁然开朗。原来__declspec(thread)这种方式在动态连接库中调用是不行的,需要自己去实现TLS存储。好吧,还是去找权威吧https://msdn.microsoft.com/en-us/library/ms686997(v=vs.85).aspx,这里写的很详细了。根据微软说明,简单封装了一下需要用到的函数,调试通过,问题解决了。
下载调试过程中的DLL源码,请移步至 http://download.csdn.net/detail/bingge1022/9870979
Tls.cpp源码
#include "Tls.h" int threadId; bool DllSet(int fdwReason) { LPVOID lpvData; BOOL fIgnore; switch (fdwReason) { // The DLL is loading due to process // initialization or a call to LoadLibrary. case DLL_PROCESS_ATTACH: // Allocate a TLS index. if ((threadId = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE; // No break: Initialize the index for first thread. // The attached process creates a new thread. case DLL_THREAD_ATTACH: // Initialize the TLS index for this thread. lpvData = (LPVOID) LocalAlloc(LPTR, 256); if (lpvData != NULL) fIgnore = TlsSetValue(threadId, lpvData); break; // The thread of the attached process terminates. case DLL_THREAD_DETACH: // Release the allocated memory for this thread. lpvData = TlsGetValue(threadId); if (lpvData != NULL) LocalFree((HLOCAL) lpvData); break; // DLL unload due to process termination or FreeLibrary. case DLL_PROCESS_DETACH: // Release the allocated memory for this thread. lpvData = TlsGetValue(threadId); if (lpvData != NULL) LocalFree((HLOCAL) lpvData); // Release the TLS index. TlsFree(threadId); break; default: break; } return TRUE; } bool StoreDataInt(int iv, int intTlsVar) { LPVOID lpvData; int * pData; // The stored memory pointer lpvData = TlsGetValue(intTlsVar); if (lpvData == NULL) { lpvData = (LPVOID) LocalAlloc(LPTR, 256); if (lpvData == NULL) return FALSE; if (!TlsSetValue(intTlsVar, lpvData)) return FALSE; } pData = (int *) lpvData; // Cast to my data type. // In this example, it is only a pointer to a int // but it can be a structure pointer to contain more complicated data. (*pData) = iv; return TRUE; } bool GetDataI(int *piv, int intTlsVar) { LPVOID lpvData; int * pData; // The stored memory pointer lpvData = TlsGetValue(intTlsVar); if (lpvData == NULL) return FALSE; pData = (int *) lpvData; (*piv) = (*pData); return TRUE; } int GetDataInt(int intTlsVar) { int ivOut; if(GetDataI(&ivOut, intTlsVar)){ return ivOut; } return -1; } bool StoreDataChar(char cv, char charTlsVar) { LPVOID lpvData; int * pData; // The stored memory pointer lpvData = TlsGetValue(charTlsVar); if (lpvData == NULL) { lpvData = (LPVOID) LocalAlloc(LPTR, 256); if (lpvData == NULL) return FALSE; if (!TlsSetValue(charTlsVar, lpvData)) return FALSE; } pData = (int *) lpvData; // Cast to my data type. // In this example, it is only a pointer to a int // but it can be a structure pointer to contain more complicated data. (*pData) = cv; return TRUE; } bool GetDataC(char *pcv, char charTlsVar) { LPVOID lpvData; int * pData; // The stored memory pointer lpvData = TlsGetValue(charTlsVar); if (lpvData == NULL) return FALSE; pData = (int *) lpvData; (*pcv) = (*pData); return TRUE; } int GetDataChar(char charTlsVar) { int cvOut; if(GetDataI(&cvOut, charTlsVar)){ return cvOut; } return -1; }
取值\赋值调用关键代码
int _intTlsVar = GetDataInt(intTlsVar); _intTlsVar = _intTlsVar+1; if(!StoreDataInt(_intTlsVar, intTlsVar)){ printf("%s","StoreData error"); }
相关文章推荐
- JNI多线程调用DLL全局变量处理,TLS实现
- Dll 中设置全局类变量, LoadLibrary 998错误, TLS问题.
- 使用JNI技术实现JAVA程序调用dll
- Chap5:使用JNI技术实现java程序调用第三方dll(c/c++)文件的功能
- 静or动态库中的全局变量被不同的dll调用修改,其值是否独立
- VC多线程中全局函数如何调用对话框类成员变量及成员函数
- 当调用的DLL中有全局变量时调用它的多个实例是否共享同一个全局变量
- Java运用JNI调用dll实现屏蔽系统热键
- java运用jni调用dll实现屏蔽系统热键和任务栏
- 静or动态库中的全局变量被不同的dll调用修改,其值是否独立?
- JAVA中利用JNI与VS2012实现C/C++的DLL调用
- java运用jni调用dll(含源码)实现屏蔽系统热键和任务栏
- 使用JNI技术实现JAVA程序调用dll
- 使用JNI技术实现JAVA程序调用dll
- java调用windows DLL实现底层处理(C++编程)
- 生成/创建 DLL 及调用/引用DLL里的函数、全局变量、静态C++类成员函数等
- JNI技术实现JAVA程序调用dll
- 使用JNI技术实现JAVA程序调用dll
- C# 调用 C++ dll 动态链接库中多个函数时全局变量的问题
- Java运用JNI调用dll实现屏蔽系统热键