【问题标题】:Howto access thread data outside a thread如何访问线程外的线程数据
【发布时间】:2011-02-10 12:09:42
【问题描述】:

问题:我在一个线程中启动 MS 文本转语音引擎,以避免 DLL_attach 崩溃。它开始正常,文本到语音引擎被初始化,但我无法在线程外访问 ISpVoice。如何在线程外访问 ISpVoice?毕竟是全局变量...

您可以在此处找到 XPThreads: http://www.codeproject.com/KB/threads/XPThreads.aspx

#include <windows.h>
#include <sapi.h>
#include "XPThreads.h"


ISpVoice * pVoice = NULL;

unsigned long init_engine_thread(void* param)
{
Sleep(5000);
    printf("lolthread\n");



    //HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    HRESULT hr = CoInitialize(NULL);

    if(FAILED(hr) )
    {
        MessageBox(NULL, TEXT("Failed To Initialize"), TEXT("Error"), 0);
        char buffer[2000] ;
        sprintf(buffer, "An error occured: 0x%08X.\n", hr);
        FILE * pFile = fopen ( "c:\\temp\\CoInitialize_dll.txt" , "w" );
        fwrite (buffer , 1 , strlen(buffer) , pFile );
        fclose (pFile);
    }
    else
    {   
        printf("trying to create instance.\n");
        //HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice);
        //hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice);
        //HRESULT hr = CoCreateInstance(__uuidof(ISpVoice), NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void **) &pVoice);
        HRESULT hr = CoCreateInstance(__uuidof(SpVoice), NULL, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice);
        if( SUCCEEDED( hr ) )
        {
            printf("Succeeded\n");
            hr = pVoice->Speak(L"The text to speech engine has been successfully initialized.", 0, NULL);
        }
        else
        {
            printf("failed\n");
            MessageBox(NULL, TEXT("Failed To Create COM instance"), TEXT("Error"), 0);
            char buffer[2000] ;
            sprintf(buffer, "An error occured: 0x%08X.\n", hr);
            FILE * pFile = fopen ( "c:\\temp\\CoCreateInstance_dll.txt" , "w" );
            fwrite (buffer , 1 , strlen(buffer) , pFile );
            fclose (pFile);
        }
    }






return NULL;
}


XPThreads* ptrThread = new XPThreads(init_engine_thread);


BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
    //init_engine();
    LoadLibrary(TEXT("ole32.dll"));
    ptrThread->Run();
    break;
case DLL_THREAD_ATTACH:
    break;
case DLL_THREAD_DETACH:
    break;
case DLL_PROCESS_DETACH:
    if(pVoice != NULL)
    {
        pVoice->Release();
        pVoice = NULL;
    }
    CoUninitialize();
    break;
}
return TRUE;
}

【问题讨论】:

  • 你能指出代码失败的地方吗?另外,您对“Dll_Attach”有什么问题?请注意,在 DllMain 中调用 LoadLibrary 是一个的想法 - 您可能会遇到 Windows 用于序列化 dll 加载的全局锁的大问题。请参阅msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx 中的备注。不确定这是否是导致问题的原因。
  • 访问问题是线程引起的,不是dllmain引起的。但是,dllmain负责强迫我使用线程,所以间接你是对的。

标签: c++ windows dll multithreading text-to-speech


【解决方案1】:

首先,您的问题是您希望在运行文件的静态初始化程序时启动的线程在您的 DllMain() 运行时已经完成,但您没有做任何事情来与它同步。当然,如果您正在做一些与它同步的事情,那么您将遇到我在回复您的other question 时发布的链接中详述的问题...

其次,COM 接口指针通常是特定于线程的。通常,您不能通过CoCreateInstance()QueryInterface() 获得一个线程,然后在另一个线程中使用它。为了能够在另一个线程中使用接口指针,您需要使用CoMarshalInterface() 之类的东西将其编组到该线程(请参阅here)。但在你这样做之前,你需要确保你已经在线程上初始化了 COM,并且由于我在回答你之前的问题时提出的所有原因,你不能这样做。

第三,你没有理由在你的DllMain() 中调用CoUninitialize(),因为a)你不知道你被调用的线程和b)你不负责调用CoInitialize()应用程序拥有的随机线程。

第四,由于this link 中指出的原因,我在回答您之前的问题时发布了对LoadLibrary() 的调用非常糟糕。

因此,总而言之,正如我在回复您的其他问题时所说,您无法在DllMain() 中做您想做的事情。这不是做这件事的地方。正如我之前所说,您可以做的是在收到DLL_PROCESS_ATTACH 通知时运行一个线程,但在这样做时遵守规则,这样您就不会死锁并在那里加载您的 COM 对象。然后,您只能从该线程访问接口指针,并且您必须进行自己的编组以将调用 DLL 的线程中的值传递到您的 COM 线程。即使那样,也可能有更好的方法来做您正在做的事情(例如将您正在构建的所有内容公开为 OWN COM 对象),但是您没有提供足够的上下文让任何人想出答案你遇到的真正问题。

哦,最后...您正在使用的 XPThreads 是基于您必须等待从 CreateThread() 返回的线程句柄的有缺陷的假设,您不需要,您可以关闭它在您创建线程之后,因为您对等待它不感兴趣。你可能想看看this question,看看为什么你可能不应该使用CreateThread(),而应该使用_beginthreadex()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多