多个线程共享变量的初始化问题

一、问题背景:

    写了一个USBManagerControl.dll动态库来监控USB设备的插拔事件,dllName.exe来加载调用USBManagerControl.dll。

部分代码如下:

/************  dllName.exe部分代码 begin   ************/
int main()
{
    hDllInst = LoadLibrary("USBManagerControl.dll");
    //......
    if (RegisterDevNotification(3))
    {
    }
    //......
}
/************  dllName.exe部分代码 end     ************/

/************  USBManagerControl.dll部分代码 begin   ************/
HWND hwnd;
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    HANDLE thread1 = NULL;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        {
            ben = GetModuleHandle(NULL);  
            thread1 = CreateThread(NULL, 0, Proc1, NULL, 0, NULL);
        }
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        {
            CloseHandle(thread1);
        }
        break;
    }
    return TRUE;
}

DWORD WINAPI Proc1(LPVOID lpParameter)  
{   
    //......
    hwnd = CreateWindow("firstwind", "zyc1", WS_OVERLAPPEDWINDOW, 500, 200, 600, 400, NULL, NULL, (HINSTANCE)ben, NULL);
    //......
    return 0;  
}

bool __stdcall  RegisterDevNotification(unsigned int devInterface)
{
    bool bReg = false;
    for (int i = 0; i < sizeof(GUID_DEVINTERFACE)/sizeof(GUID); i++)
    {
        HDEVNOTIFY hDeviceNotify;
        //通过注册窗口句柄hwnd的方式来监听USB设备的插拔事件
        DoRegisterDeviceInterfaceToHwnd(GUID_DEVINTERFACE[i], hwnd, &hDeviceNotify);
        bReg = true;
    }
    return bReg;
}
/************  USBManagerControl.dll部分代码 end     ************/

问题:

    在VS上直接进行debug模式的调试没有问题,而直接运行编译好的dllName.exe则总是监听不到USB设备的插拔事件。

二、分析:

    在代码中添加日志,发现直接运行dllName.exe时,在dllName.exe调用DoRegisterDeviceInterfaceToHwnd时,窗口句柄为NULL,即还没有创建好。估计是在vs中直接进行debug模式的调试时,先加载了DLL,DLL里的线程thread1在dllName.exe调用注册接口时先执行了,所以窗口句柄在注册之前就已创建好。

    解决方法就是确保在执行注册窗口句柄hwnd之前,窗口句柄已经创建成功。则可以通过创建一个事件,等窗口句柄hwnd创建成功后,再通知注册窗口句柄hwnd的方式解决。修改后的代码如下:

/************  dllName.exe部分代码 begin   ************/
int main()
{
    hDllInst = LoadLibrary("USBManagerControl.dll");
    //......
    if (RegisterDevNotification(3))
    {
    }
    //......
}
/************  dllName.exe部分代码 end     ************/

/************  USBManagerControl.dll部分代码 begin   ************/
HWND hwnd;
HANDLE g_Event;
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    HANDLE thread1 = NULL;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        {
            g_Event = CreateEvent(NULL, false, false, NULL);
            ben = GetModuleHandle(NULL);  
            thread1 = CreateThread(NULL, 0, Proc1, NULL, 0, NULL);
        }
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        {
	        CloseHandle(thread1);
        }
        break;
    }
    return TRUE;
}

DWORD WINAPI Proc1(LPVOID lpParameter)  
{   
    //......
    hwnd = CreateWindow("firstwind", "zyc1", WS_OVERLAPPEDWINDOW, 500, 200, 600, 400, NULL, NULL, (HINSTANCE)ben, NULL);
    ::SetEvent(g_Event);
    //......
    return 0;  
}

bool __stdcall  RegisterDevNotification(unsigned int devInterface)
{
    bool bReg = false;
    WaitForSingleObject(g_Event, INFINITE);//等待窗口句柄hwnd创建成功
    for (int i = 0; i < sizeof(GUID_DEVINTERFACE)/sizeof(GUID); i++)
    {
        HDEVNOTIFY hDeviceNotify;
        //通过注册窗口句柄hwnd的方式来监听USB设备的插拔事件
        DoRegisterDeviceInterfaceToHwnd(GUID_DEVINTERFACE[i], hwnd, &hDeviceNotify);
        bReg = true;
    }
    return bReg;
}
/************  USBManagerControl.dll部分代码 end     ************/

三、总结

    如上代码所示,解决方案通过windows的CreateEvent、SetEvent 和 WaitForSingleObject 三个函数实现不同线程间事件通知的目的,从而保证在多个线程时,所有线程中的变量都初始化完成后,再执行其他操作。

猜你喜欢

转载自blog.csdn.net/zangyongcan/article/details/81568676