我写了一个win32 dynamic link library,大体如下: 
int a=1;//变量a因为在fun1和fun2函数中都要用到,所以在函数体外初始化 
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) 

    switch(ul_reason_for_call) 
    { 
    case DLL_PROCESS_ATTACH: 
    case DLL_THREAD_ATTACH: 
    case DLL_THREAD_DETACH: 
    case DLL_PROCESS_DETACH: 
    } 
    return TRUE; 

fun1() 

...... 

fun2() 

...... 
} 第一个线程调用dll时,将a值由1改为0。第二个线程调用dll时a的初始值就为0了。我希望第二个线程调用dll时a的初始值仍然为1,应该如何做?是不是a初始化的地方不对?高手救我!

解决方案 »

  1.   

    你的要求貌似线程本地存储,改成__declspec(thread) int a=1;试试。不敢肯定在DLL里是否有效,如果不行的话只能用Tlsxxx的API来做了,MSDN里有示例:
    Using Thread Local Storage in a Dynamic-Link Library
    ms-help://MS.MSDNQTR.v90.chs/dllproc/base/using_thread_local_storage_in_a_dynamic_link_library.htm
      

  2.   

    如果不能从源头控制,那就将DLL复制成多个副本,每个线程各调一个副本。
      

  3.   

    楼主的处理逻辑不是很好
    如果你要第二个线程调用a的初始值仍为1,那么何不每个线程load一个DLL的实例
    而如果你多个线程要共同访问一个DLL实例的资源,为什么要苛求第二个线程调用a的初始值仍为1
      

  4.   

    上面几楼的高手,我试过改成__declspec(thread) int a=1;不行
    于是用第二种方法就是tls,我这样写的,
    fun1() 

      LPVOID lpvData;   lpvData = TlsGetValue(dwTlsIndex); 
    ...... 

    fun2() 

      LPVOID lpvData;   lpvData = TlsGetValue(dwTlsIndex); 
    ...... 

    按照我上面的这种写法是不是fun1和fun2里的lpvData指针是同一个指针? 
    可是我调试的时候为什么它们的地址不一样呢?我希望的是变量在fun1里更改之后,在fun2中该变量的值也同样更改。否则我之前也不会把它定义在函数体外了。
      

  5.   

    是的啊,我现在只是在一个线程里调用dll而已,结果在2个函数里指向不同地址,怎么会这样?
      

  6.   

    DLL代码:
    #include <windows.h>
    static DWORD dwTlsIndex;int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    {
        switch (reason)
        {
            case DLL_PROCESS_ATTACH:
                dwTlsIndex = TlsAlloc();
                //no break;
            case DLL_THREAD_ATTACH:
                TlsSetValue(dwTlsIndex,LPVOID(1));  // 为每个进入的线程初始化为1
                break;
            case DLL_PROCESS_DETACH:
                TlsFree(dwTlsIndex);
                break;
            case DLL_THREAD_DETACH:
                break;
        }
        return 1;
    }
    //---------------------------------------------------------------------------
    extern "C" void __declspec(dllexport) __stdcall SetValue(LPVOID value)  // 赋值
    {
        TlsSetValue(dwTlsIndex,value);
    }extern "C" LPVOID  __declspec(dllexport) __stdcall fun1()  // 取值
    {
      return TlsGetValue(dwTlsIndex);}
    extern "C" LPVOID  __declspec(dllexport) __stdcall fun2()  // fun2和fun1是一样的,只是试试两个函数内调用结果是否相同
    {
      return TlsGetValue(dwTlsIndex);}多线程调用dll程序的代码:#include <windows.h>
    #include <iostream>
    #include <process.h>extern "C" void __declspec(dllimport) __stdcall SetValue(LPVOID value);
    extern "C" LPVOID  __declspec(dllimport) __stdcall fun1();
    extern "C" LPVOID  __declspec(dllimport) __stdcall fun2();using namespace std;CRITICAL_SECTION g_csCOUT;    // 为cout建一个临界区,不然显示结果很乱void thread_code(void *threadno)
    {
        int nValue = (int)fun1();
        for(int i = 0; i< 10; i++)
        {
            SetValue( LPVOID(++nValue) );        EnterCriticalSection(&g_csCOUT);
            cout << (int)threadno << " : " << (int)fun2() << endl;
            LeaveCriticalSection(&g_csCOUT);
        }
    }
    int main(int argc, char* argv[])
    {
        ::InitializeCriticalSection(&g_csCOUT);    int nFun1Result = (int) fun1();
        int nFun2Result = (int) fun2();
        cout << "fun1() return :" << nFun1Result << endl;   
        cout << "fun2() return :" << nFun2Result << endl;  // 两个结果相同,都为1    SetValue(LPVOID(1234));
        nFun1Result = (int) fun1();
        nFun2Result = (int) fun2();                       
        cout << "=================================" << endl;
        cout << "fun1() return :" << nFun1Result << endl;
        cout << "fun2() return :" << nFun2Result << endl; // 两个结果相同,都为1234    cout << "=================================" << endl;
        for(int i=0; i<5; i++)
            _beginthread(thread_code,4096,(void *)i);    // 建立5个线程,结果显示各个线程内的SetValue只影响此线程本身,不会互相干扰    system("pause");    ::DeleteCriticalSection(&g_csCOUT);
        return 0;
    }
      

  7.   

    waiting4you,谢谢你。其实我昨天试过msdn上的例子,是没有问题的,但是我自己的应用程序调用就不行。msdn的例子是win32控制台程序,我的应用程序是基于对话框的mfc程序。不知道这种dll对调用它的应用程序有没有什么限制和要求。
    我再检查一下我的应用程序,再试试你提供的代码。有问题再问你。多谢你!
      

  8.   

    waiting4you,我现在知道原因了,不好意思啊,之前我没有理解正确误导你们了!
    我的fun1和fun2不在同一个线程函数里面。事实上我的要求是这样的,
    我写了一个类Class,大体如下:
    DWORD Class::fun()    //任意一个函数
    {
    fun1()
    ......
    }
    DWORD Class:Thread_fun()  //线程函数
    {
    fun2()
    ......
    }
    这个类Clss对应多个实例,我希望每个实例调用dll互不干扰。有什么办法可以实现呢?
    谢谢!
      

  9.   

    我想到一个比较笨的解决办法,就是在fun1和fun2函数里增加一个索引号作为函数参数,然后变量a还是定义在外面,但是在fun1开头初始化。每个实例调用dll时索引号不同就不会干扰了。也不知道这样做是否安全?测试了一小会暂时还没有问题
      

  10.   

    我曾经是这样解决的:
    不使用全局变量, 在DLL加载的时候, 去判断是否存在命名FIleMAPPING对象,没有就建立,其值为你的初始值; 如果有,其值就是你的全局变量值.
    在每个线程访问的时候使用临界区读写全局变量. 在每次需要用到的地方都需要去访问这个内核对象.
    效率上应该不会太低. 不过确实可以保证多线程DLL的变量共享.