4

我正在开发一个多线程的 win32 MFC 应用程序。我们正在渲染地图并将其与顶部的自定义渲染对象一起显示在用户界面的窗格中。渲染速度很慢(~800 毫秒),这发生在用户界面线程上。

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

我看到的是线程创建了一个新的CBitmapvia CreatCompatibleBitmap,然后尝试将新CBitmap对象选择到 Draw 线程的CDC.

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()中出现debug 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方法返回错误的对象?我CDC为 Draw 线程创建一个,然后一遍又一遍地重复使用它的方式是否存在根本缺陷?有什么方法可以帮助调试/解决这个问题吗?

4

1 回答 1

2

金的。句柄和对象之间的映射在线程本地存储中。

在多线程环境中,因为窗口由线程拥有,MFC 将临时和永久的窗口句柄映射保存在线程本地存储中。其他句柄映射也是如此,例如 GDI 对象和设备上下文的句柄映射。将窗口句柄映射保存在线程本地存储中可确保防止多个线程同时访问。

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

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

于 2009-10-16T17:23:31.290 回答