Multithreading AFXcurrentSourceHandle中MFC中的数据竞争

Multithreading AFXcurrentSourceHandle中MFC中的数据竞争,multithreading,mfc,Multithreading,Mfc,我们在基于MFC的应用程序中遇到了一个与“当前MFC状态”和线程相关的问题。在主线程中,我们称之为VisualManager,因为我们希望有漂亮的工具栏。调用在afxvisualmanageroffice2007.cpp中的CMFCVisualManagerOffice2007::onUpdate系统颜色函数中结束,该函数通过调用AfxSetResourceHandle函数更改“当前资源句柄”。此函数获取“当前模块状态”,并将“当前资源句柄”从MyApp.exe更改为mfc140u.dll。这很

我们在基于MFC的应用程序中遇到了一个与“当前MFC状态”和线程相关的问题。在主线程中,我们称之为VisualManager,因为我们希望有漂亮的工具栏。调用在
afxvisualmanageroffice2007.cpp
中的
CMFCVisualManagerOffice2007::onUpdate系统颜色
函数中结束,该函数通过调用
AfxSetResourceHandle
函数更改“当前资源句柄”。此函数获取“当前模块状态”,并将“当前资源句柄”从
MyApp.exe
更改为
mfc140u.dll
。这很好,因为VisualManager的资产位于该DLL中,在所有情况下,更改都将恢复到
MyApp.exe

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

所以,我的问题是:1)管理基于MFC的线程是否有明显的错误?我们是否应该以某种方式复制或保护“模块状态”,使新线程不受主线程所做更改的影响?MFC是否应该创建类似于每线程变量/状态的东西?2) 我认为Microsoft在这方面是错误的,更改了实际上是全局变量的内容并改变了其他线程的期望,VisualManager应该获得句柄并将其作为参数传递给所有函数。我说得对吗

编辑:

嗨,伙计们,@iinspectable,@cha,我有一个更新,很抱歉花了这么长时间。复制步骤:打开Visual Studio 2015 Update 3,通过向导创建新的MFC应用程序,确保它的“项目样式”和“视觉样式和颜色”选择为“Office”和“Office 2007(蓝色主题)”。从MSVS文件夹中打开文件
afxvisualmanagerofice2007.cpp
,并将4个断点放入
cmfcvisualmanagerofice2007::OnUpdateSystemColors
函数,在该函数中调用
AfxSetResourceHandle
。在新创建的项目文件夹中打开文件
mfcapapplication1.cpp
,并将此代码[1]放入
CMFCApplication4App::InitInstance
函数中
CMainFrame*pMainFrame=new CMainFrame,将断点放入此线程进程

现在,在调试模式下构建并运行这个MFC应用程序,在每个断点命中时,使用线程窗口中的冻结线程和解冻线程函数,因此,您将在 CMFCVisualMaungOffice 2007::在使用“<代码> AfxSetResourceHandle < /COD>函数”和“工作线程在<代码> CSTrutt::LoadString < /代码>之前设置全局变量之后,将主线程安排在<代码> CMFCVisualMaungService Office 2007::OnUpDeDistSisteSo色彩函数中。现在加载字符串将失败,因为它正在
mfc140ud.dll
中查找它,而不是使用资源链和
mfcapapplication1.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.

不知何故,你做错了。每个线程管理“当前”(或“活动”)模块状态。请同时参阅。@IInspectable这两篇文章讨论了模块状态,我相信我不需要处理模块状态,我需要更改每个线程的模块状态指针,指向有意义的内容,或者不允许在主线程中进行此更改。主线程的模块状态指向全局模块状态,而另一个线程的模块状态为空,因此它使用全局模块状态,该状态现在已切换/损坏一段时间。是的,如果您中断模块状态管理,框架将无法为您修复。解决方案是不破坏模块状态管理。部分解决方案是确保您的线程是
CWinThread
派生的。@I不可检测哦,我相信我没有破坏状态管理,我只是通过调用
AfxBeginThread
启动了新线程,它创建
CWinThread
,我相信这是创建MFC管理线程的正确方法。这条新的线看到地面在下面移动,这很不幸,我想以某种方式阻止它。顺便说一句,即使只有一个“module”
MyApp.exe
,我也不会在任何地方显式更改该模块。请使用从应用程序资源加载字符串。不要使用
LoadString(UINT-nID)