最近公司项目用到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");
}
相关推荐
完整的实现java跨平台调用C程序源码,包含JAVA源码和C源码以及编译后的demo dll。将dll放到jdk bin目录下,java 项目可以...该demo处理了多线程调用c,全局变量干扰问题。源码全是自己写的,整个过程以及结果完整验证
本项目主要是实现了在jni中用多线程调用java对象。代码调试通过。直接导入到eclipse即可运行
C/C++的跨平台调用,DLL多线程全局变量互相干扰的处理,dll源码,测试过的代码 不包含JNI调用的JAVA端源码。
Java通过JNI调用DLL动态库,亲测试编写
[JAVA]使用JNI技术实现JAVA程序调用dll、[JAVA]使用JNI技术实现JAVA程序调用dll
C++使用JNI多线程回调java代码例子,因为依赖了我的一些库和头文件,没有传上去,编译不过,但是大家可以参考一下,如何使用C++多线程调用java函数
请C++同事帮忙写个dll程序,dll去解析开发平台输出的二进制流数据,上层应用平台调用dll得到json报文,然后再去做一些业务处理。 那现在上层应用面临的问题:访问java外部功能接口实现方式(即调用dll)怎么选择及...
设计一个多线程, 并且实现同步, 我理解的多线程需求如下: 1. 线程在Java端启动, 两个线程都调用C的方法 2. 有一个共同的数据, 被C的代码修改, 要求线程能对这个修改做同步, 即线程1
springboot+jna/jni调用动态so/dll库
通过JNI接口静态注册的native方法去创建线程,同时提供native回调Java的方法。通过这个框架可以去实现线程监听某一个状态,然后回调Java的方法(如发消息去通知顶层,实现显示)
该Demo有两个主要的例子,一个实现的是在java程序中调用DLL中的方法;而一个则是讲述如何在C++代码中调用Java类中的方法、详细阐述了JNI机制的使用,是一个很好的学习例子。
Java通过JNI调用C++接口,Demo文档描述(里面有代码),里面有Windows下调用版和linux下调用版,经本人亲自测试,可用。
这两天要弄个JAVA调用DLL,研究了一下有点绕, java部分要生成.h头文件,所以弄了个例子在这分享下 JAVA调用DLL完整步骤 步骤里包括java部分代码及vc写的DLL代码
在JAVA中如何通过JNI调用VC动态库,以及在如何在VC中调试
我们知道,使用 JNI 调用 .dll/.so 共享类库是非常非常麻烦和痛苦的。 假如有一个现有的 .dll/.so 文件,假如使用 JNI 技术调用,我们首先需要另外使用 C 语言写一个 .dll/.so 共享库,使用 SUN 规定的数据结构替换 ...
本资源包括JAVA工程,C++工程,C#dll测试工程
jni调用c++ delphi中的dll.
java 调用 dll 的方法,即JNI的使用,demo中有get()/set()方法,操作步骤详细,即使是没用过java的程序员按照步骤依然可以成功。
在JNI层使用多线程进行同步,项目是Eclipse 有喜欢的,可加评论,返积分哦
基于最新版本的gmssl,实现了java通过jni调用gmssl,可使用国密sm2算法、sm3算法和sm4算法,包括jni的动态库和java调用示例