MFC中的数据竞争afxCurrentResourceHandle

时间:2017-01-30 16:33:42

标签: multithreading mfc

我们在与“当前MFC状态”和线程相关的基于MFC的应用程序中存在问题。在主线程中我们调用VisualManager,因为我们想要有花哨的工具栏。该调用最终位于CMFCVisualManagerOffice2007::OnUpdateSystemColors内的afxvisualmanageroffice2007.cpp函数中,该函数通过调用AfxSetResourceHandle函数来更改“当前资源句柄”。此函数获取“当前模块状态”并将“当前资源句柄”从MyApp.exe更改为mfc140u.dll。这很好,因为VisualManager的资源位于该DLL中,并且在所有情况下更改都将恢复为MyApp.exe

然而,不好的是我们在调用VisualManager之前生成一个新线程(通过使用AfxBeginThread),这个线程需要从字符串表中加载一些字符串(通过使用CString类),但它有时不这样做。它失败了,因为有关于AFX_MODULE_STATE::m_hCurrentResourceHandle变量的主线程的竞争。线程期望将其设置为MyApp.exe,但主线程将其更改为mfc140u.dll并返回,“当前资源句柄”实际上是一个全局变量。

所以,我的问题是:1)我们在管理基于MFC的线程时是否做了明显错误的事情?我们应该以某种方式复制或保护“模块状态”,以便我们的新线程能够免受主线程所做的更改吗?应该瞄准MFC创建像每线程变量/状态的东西? 2)我认为微软在这里是错误的,改变实际上是一个全局变量并拧紧其他线程的期望,VisualManager应该获取句柄并将其作为参数传递给它的所有函数。我是对的吗?

编辑:

大家好@iinspectable,@ cha,我有更新,抱歉花了这么长时间。重现步骤:打开Visual Studio 2015 Update 3,通过向导创建新的MFC应用程序,确保它具有"项目样式"和#34;视觉风格和颜色"被选为" Office"和#34; Office 2007(蓝色主题)"。从MSVS文件夹中打开文件afxvisualmanageroffice2007.cpp,并将4个断点放入CMFCVisualManagerOffice2007::OnUpdateSystemColors函数中,并调用AfxSetResourceHandle。在新创建的项目文件夹中打开文件MFCApplication1.cpp,并在CMFCApplication4App::InitInstance之前将此代码[1]放入CMainFrame* pMainFrame = new CMainFrame;函数中,将断点放入此线程proc。

现在在调试模式下构建并运行这个MFC应用程序,在每个断点命中,使用冻结线程并从Threads窗口解冻线程函数,这样你就可以在CMFCVisualManagerOffice2007::OnUpdateSystemColors函数中间安排主线程了使用AfxSetResourceHandle函数和CStringT::LoadString之前的工作线程设置全局变量。现在,加载字符串将失败,因为它在mfc140ud.dll内查找它而不是使用资源链和MFCApplication1.exe

我相信这是微软的错误(暂时改变全局变量),我的代码库充满了无辜的CString::LoadString调用,这些调用依赖于使用各种插件精心构建的资源链DLL和最后的.exe。如果这不是微软的错误,那么依靠MFC为我提供可用的资源链是我的错误。我需要创建自己的类似资源链的功能,并在从资源加载字符串和其他东西时随处使用它。

// [1]
AFX_THREADPROC thread_proc = [](LPVOID pParam){
    CString str;
    str.LoadString(IDS_CAPTION_TEXT);
    UINT ret = 0;
    return ret;
};
::AfxBeginThread(thread_proc, (LPVOID)nullptr);
// Same result with ::AfxBeginThread(CRuntimeClass*) overload.

0 个答案:

没有答案