c – ASSERT在CDC SelectObject()调用失败 – 我可以尝试什么?

我正在研究多线程win32 MFC应用程序.我们正在渲染地图并将其显示在用户界面的窗格中以及顶部的自定义渲染对象.渲染速度很慢(~800 ms),这在用户界面线程上发生.

我正在尝试将渲染移动到自己的线程上,以便菜单仍然保持活泼,而其他渲染仍然可以在后台运行. Draw线程将使用自己的CDC不断渲染. UI线程将调用重绘函数,该函数锁定互斥锁,并获取CBitmap的最后一个快照并使用UI的CDC绘制它.使用Draw线程的CDC的每个位置都被互斥锁锁定.

我所看到的是通过CreatCompatibleBitmap创建新CBitmap的线程,然后尝试在Draw线程的CDC中选择新的CBitmap对象.

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的方式是否存在根本缺陷,然后一遍又一遍地重复使用?我可以采取任何方法来帮助调试/解决此问题吗?

最佳答案 金.句柄和对象之间的映射在
thread-local storage中.

In a multi-threaded environment
because windows are owned by threads,
MFC keeps the temporary and permanent
window handle map in thread local
storage. The same is true for other
handle maps like those for GDI objects
and device contexts. Keeping the
window handle maps in thread local
storage ensures protection against
simultaneous access by several
threads.

所以基本上,存储句柄,然后从句柄创建一个CBitmap,以便在线程之间操作它们.

我的错误是在UI线程中创建我的CBitmap,然后从两个线程访问CBitmap对象.

点赞