JNI多线程调用DLL全局变量处理,TLS实现

2 篇文章 0 订阅
1 篇文章 0 订阅

        最近公司项目用到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");


 }


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java多线程可以调用DLL(Dynamic-Link Library)来进行一些特定操作。 首先,在Java中调用DLL需要使用到Java Native Interface(JNI)技术。JNI是Java提供的一种机制,用于在Java程序中调用本地的C/C++代码。通过JNI,我们可以在Java程序中加载和调用DLL中的函数。 在多线程调用DLL的过程如下: 1. 首先,在Java中编写一个JNI的接口类,用于定义与DLL中函数的映射关系。这个接口类需要使用Java的native关键字来声明与DLL中函数对应的本地方法。 2. 在DLL实现与接口类中声明的本地方法对应的C/C++函数。这些函数可以通过DLL导出符号的方式供Java程序调用。 3. 在Java程序中加载DLL调用其中的函数。 使用多线程调用DLL时,需要注意以下几点: 1. 线程安全性:在多线程环境下调用DLL时,需要确保DLL中的函数是线程安全的,即能够正确处理多个线程间的共享数据。 2. 同步控制:如果DLL中的函数需要访问共享资源,需要在Java程序中使用同步控制机制,如synchronized关键字或Lock对象来确保线程之间的互斥访问。 3. 线程间通信:如果多个线程需要相互通信,可以通过共享内存或消息传递的方式实现。在DLL中可以使用线程同步的机制来实现线程间的互斥、等待和通知操作。 总之,Java多线程可以通过JNI技术调用DLL来完成一些底层的特定操作。在进行多线程调用DLL时,需要保证线程安全性,确保合适的同步控制和线程间通信方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值