我正在研究多线程win32 MFC应用程序。我们正在渲染地图并将其显示在用户界面的窗格中以及顶部的自定义渲染对象。渲染速度很慢(~800 ms),这发生在用户界面线程上。
我正在尝试将渲染移动到自己的线程上,以便菜单仍然保持活泼,而其他渲染仍然可以在后台运行。 Draw线程将使用自己的CDC不断渲染。 UI线程将调用重绘函数,该函数锁定互斥锁,并获取CBitmap
的最后一个快照,并使用UI的CDC
绘制它。使用Draw线程的CD
C的每个位置都被互斥锁锁定。
我看到的是通过CBitmap
创建新CreatCompatibleBitmap
的线程,然后尝试在Draw线程的CBitmap
中选择新的CDC
对象。< / p>
this->m_canvas.CreateCompatibleDC(&compatibleDC);
this->m_bitmap = new CBitmap();
this->m_bitmap->CreateCompatibleBitmap(&compatibleDC, m_width, m_height);
m_oldBitmap = this->m_canvas.SelectObject(m_bitmap);
此时,CGdiObject :: FromHandle()中存在调试ASSERT失败。
CGdiObject* PASCAL CGdiObject::FromHandle(HGDIOBJ h)
{
CHandleMap* pMap = afxMapHGDIOBJ(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CGdiObject* pObject = (CGdiObject*)pMap->FromHandle(h);
ASSERT(pObject == NULL || pObject->m_hObject == h);
return pObject;
}
第二个ASSERT
失败,因为m_hObject
与传入的句柄不匹配。基本上,MFC正在获取句柄,并进行查找以获取某个CBitmap
对象与刚刚创建的CBitmap
不匹配。
这听起来对任何人都很熟悉吗?可能会发生什么导致FromHandle
方法返回错误的对象?我为Draw线程创建CDC
的方式是否存在根本缺陷,然后反复使用它?我可以采取任何方法来帮助调试/解决此问题吗?
答案 0 :(得分:2)
金。句柄和对象之间的映射位于thread-local storage。
在多线程环境中 因为windows是由线程拥有的, MFC保持临时和永久 线程局部的窗口句柄映射 存储。其他人也是如此 处理像GDI对象那样的地图 和设备上下文。保持 线程本地的窗口句柄映射 存储确保防范 几个人同时访问 线程。
所以基本上,存储句柄,然后从句柄创建一个CBitmap,以便在线程之间操作它们。
我的错误是在创建我的CBitmap的UI线程中,然后从两个线程访问CBitmap对象。