经常遇到的一个问题是 MFC中开启多线程后 在非主线程中使用updata函数出现崩溃的情况。
来源:互联网 发布:恒宝充电器淘宝店 编辑:程序博客网 时间:2024/05/17 03:32
经常遇到的一个问题是 MFC中开启多线程后 在非主线程中使用updata函数出现崩溃的情况。
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
lpThis->UpdateData(FALSE);
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
点击按钮后出现如下问题
(一般方法不讲:就是传入this指针setwindowtext等)
下面我们通过具体调试来解决这个问题
F5启动程序点击按钮出现错误提示后点击重试
查看堆栈黄箭头是报错的地方,绿箭头是我们的代码位置
看看出错的位置代码情况
#ifdef _DEBUG
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return;
ASSERT(HWND_TOP == NULL);
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
ASSERT(::IsWindow(m_hWnd));
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CObject* p;
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us//这一句关键
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
}
}
ASSERT((CWnd*)p == this); 这一句会检查CWnd对象是否是自己 如果不是则崩溃,
再看上面的代码 p如何拿到的我们也学会了,知道错误的原因,我们就可以解决了
也就是把这个p对象换成自己的
根本的是吧CHandleMap* pMap = afxMapHWND(); 或称自己的
这个数据怎么来呢,MFC是有自己的线程模块状态 现获取这个状态Afx
AfxGetModuleThreadState();
AFX_MODULE_THREAD_STATE
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
// list of CFrameWnd objects for thread
CTypedSimpleList<CFrameWnd*> m_frameList;
// temporary/permanent map state
DWORD m_nTempMapLock; // if not 0, temp maps locked
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
// thread-local MFC new handler (separate from C-runtime)
_PNH m_pfnNewHandler;
#ifndef _AFX_NO_SOCKET_SUPPORT
// WinSock specific thread state
HWND m_hSocketWindow;
#ifdef _AFXDLL
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle;
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets;
CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications;
#else
CMapPtrToPtr* m_pmapSocketHandle;
CMapPtrToPtr* m_pmapDeadSockets;
CPtrList* m_plistSocketNotifications;
#endif
#endif
};
CHandleMap* pMap = NULL;
CHandleMap* pMap2 = NULL;
char* lpdata = "Hello";
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
pMap2 = AfxGetModuleThreadState()->m_pmapHWND;
AfxGetModuleThreadState()->m_pmapHWND = pMap;替换成主模块的
lpThis->UpdateData(FALSE);
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
运行起来看看是否实现了
结果还是错误的
挂在这里 访问失败
看堆栈往上找
我们updata之后应该吧线程模块状态再次恢复
所以代码应该改成这样
CHandleMap* pMap = NULL;
CHandleMap* pMap2 = NULL;
char* lpdata = "Hello";
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
pMap2 = AfxGetModuleThreadState()->m_pmapHWND;
AfxGetModuleThreadState()->m_pmapHWND = pMap;
lpThis->UpdateData(FALSE);
AfxGetModuleThreadState()->m_pmapHWND = pMap2;
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
在运行就不崩溃了
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
lpThis->UpdateData(FALSE);
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
点击按钮后出现如下问题
(一般方法不讲:就是传入this指针setwindowtext等)
下面我们通过具体调试来解决这个问题
F5启动程序点击按钮出现错误提示后点击重试
查看堆栈黄箭头是报错的地方,绿箭头是我们的代码位置
看看出错的位置代码情况
#ifdef _DEBUG
void CWnd::AssertValid() const
{
if (m_hWnd == NULL)
return;
ASSERT(HWND_TOP == NULL);
if (m_hWnd == HWND_BOTTOM)
ASSERT(this == &CWnd::wndBottom);
else if (m_hWnd == HWND_TOPMOST)
ASSERT(this == &CWnd::wndTopMost);
else if (m_hWnd == HWND_NOTOPMOST)
ASSERT(this == &CWnd::wndNoTopMost);
else
{
ASSERT(::IsWindow(m_hWnd));
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CObject* p;
ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
(p = pMap->LookupTemporary(m_hWnd)) != NULL);
ASSERT((CWnd*)p == this); // must be us//这一句关键
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
}
}
ASSERT((CWnd*)p == this); 这一句会检查CWnd对象是否是自己 如果不是则崩溃,
再看上面的代码 p如何拿到的我们也学会了,知道错误的原因,我们就可以解决了
也就是把这个p对象换成自己的
根本的是吧CHandleMap* pMap = afxMapHWND(); 或称自己的
这个数据怎么来呢,MFC是有自己的线程模块状态 现获取这个状态Afx
AfxGetModuleThreadState();
AFX_MODULE_THREAD_STATE
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
// list of CFrameWnd objects for thread
CTypedSimpleList<CFrameWnd*> m_frameList;
// temporary/permanent map state
DWORD m_nTempMapLock; // if not 0, temp maps locked
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
// thread-local MFC new handler (separate from C-runtime)
_PNH m_pfnNewHandler;
#ifndef _AFX_NO_SOCKET_SUPPORT
// WinSock specific thread state
HWND m_hSocketWindow;
#ifdef _AFXDLL
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle;
CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets;
CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications;
#else
CMapPtrToPtr* m_pmapSocketHandle;
CMapPtrToPtr* m_pmapDeadSockets;
CPtrList* m_plistSocketNotifications;
#endif
#endif
};
CHandleMap* pMap = NULL;
CHandleMap* pMap2 = NULL;
char* lpdata = "Hello";
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
pMap2 = AfxGetModuleThreadState()->m_pmapHWND;
AfxGetModuleThreadState()->m_pmapHWND = pMap;替换成主模块的
lpThis->UpdateData(FALSE);
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
运行起来看看是否实现了
结果还是错误的
挂在这里 访问失败
看堆栈往上找
我们updata之后应该吧线程模块状态再次恢复
所以代码应该改成这样
CHandleMap* pMap = NULL;
CHandleMap* pMap2 = NULL;
char* lpdata = "Hello";
UINT MyThread(LPVOID p)
{
CAbDlg* lpThis = (CAbDlg*)p;
lpThis->m_str = lpdata;
pMap2 = AfxGetModuleThreadState()->m_pmapHWND;
AfxGetModuleThreadState()->m_pmapHWND = pMap;
lpThis->UpdateData(FALSE);
AfxGetModuleThreadState()->m_pmapHWND = pMap2;
return 0;
};
void CAbDlg::OnButton1()
{
pMap = AfxGetModuleThreadState()->m_pmapHWND;
AfxBeginThread(MyThread, this);
}
在运行就不崩溃了
0 0
- 经常遇到的一个问题是 MFC中开启多线程后 在非主线程中使用updata函数出现崩溃的情况。
- 在ListView控件中添加head视图为ViewPager时遇到的问题是滑动出现混乱。
- 在MFC中使用OCX控件遇到的一个问题
- 数据量的问题是很多面试笔试中经常出现的问题
- WebBrowser在非主线程的线程中创建
- 实现开启一个activity后,不出现在对应的recent列表中
- 黑马程序员-多线程-在android开发中经常会遇到从子线程切换到主线程,但是频繁地切换会使代码变得很臃肿,也不好维护,想请教一下各位大牛都是怎么处理的?
- 关于handler在非主线程中充当计时器使用的疑问
- 在项目中经常遇到的问题
- 在Maven项目中经常遇到找不到包 或者找不到配置文件的情况
- 在vs10中处理多线程MFC遇到的问题
- 在非启动项目中使用实体数据模型、wcf服务等控件时,经常出现的问题
- 在R12版本中月末关帐时经常会出现关不了的情况
- getView中经常出现position=0的情况
- 关于MFC中数据收发后出现的指针为空或数据数组崩溃毁坏
- 面试中经常遇到的问题(非技术)
- 在Updata语句中使用参数
- C++中,经常有同名成员函数,一个const形式一个非const形式的解读
- 微信公众号开发4图文消息
- DelayQueue
- python查看安装了哪些模块
- win10专业版激活方法
- ngnix笔记
- 经常遇到的一个问题是 MFC中开启多线程后 在非主线程中使用updata函数出现崩溃的情况。
- 春节如何应对三姑六婆严词拷问!
- 【牛客网】网易2017内推笔试编程题合集(二)
- (现实项目管理神器) jira使用介绍
- Java多线程之线程池使用
- rabbitmq基础
- html 使用 Jquery 懒加载 与 webp 整合优化
- 《马克思主义与社会科学方法论》知识梳理
- Ubuntu GPG 加密邮件