Сбой ASSERT при вызове CDC SelectObject () - что я могу попробовать?

Я работаю над многопоточным приложением Win32 MFC. Мы визуализируем карту и отображаем ее на панели в пользовательском интерфейсе вместе с настраиваемыми объектами наверху. Рендеринг выполняется медленно (~ 800 мс), что происходит в потоке пользовательского интерфейса.

Я пытаюсь переместить рендеринг в отдельный поток, чтобы меню оставались быстрыми, в то время как другой рендеринг мог работать в фоновом режиме. Поток Draw будет непрерывно отображать, используя собственный CDC. Поток пользовательского интерфейса вызовет функцию перерисовки, которая блокирует мьютекс, берет последний снимок CBitmap и рисует его с помощью CDC пользовательского интерфейса. Каждое место, где используется CDC потока Draw, блокируется мьютексом.

Я вижу, что поток создает новый CBitmap через CreatCompatibleBitmap, а затем пытается выбрать новый объект CBitmap в CDC потока Draw.

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);

На этом этапе произошла ошибка ASSERT отладки в CGdiObject :: FromHandle ().

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, а затем использую его снова и снова? Есть ли какие-либо подходы, которые я могу предпринять, чтобы помочь отладить / решить эту проблему?


person Kieveli    schedule 16.10.2009    source источник
comment
Это определенно странно: когда вы находитесь в CGdiObject :: FromHandle (), мы обрабатываем возвращаемое значение из :: SelectObject (), и не очевидно, как это может пойти не так. Выглядит ли pObject как действительный объект при выполнении assert?   -  person DavidK    schedule 16.10.2009
comment
да. pObject действителен, и CBitmap ... но не тот же CBitmap, созданный в операторе new Bitmap ().   -  person Kieveli    schedule 16.10.2009
comment
Для каждого потока существует один дескриптор - ›карта поиска объектов ... Я создавал CBitmap в одном потоке, а затем пытался использовать его в другом ... поиск в карте не удался.   -  person Kieveli    schedule 16.10.2009


Ответы (1)


Золотой. Сопоставление дескрипторов и объектов находится в локальном хранилище потока.

В многопоточной среде, поскольку окна принадлежат потокам, MFC хранит временную и постоянную карту дескрипторов окна в локальном хранилище потока. То же самое верно и для других карт дескрипторов, например, для объектов GDI и контекстов устройств. Хранение карт дескрипторов окон в локальном хранилище потоков обеспечивает защиту от одновременного доступа нескольких потоков.

По сути, сохраните дескриптор, а затем создайте CBitmap из дескриптора, чтобы манипулировать ими между потоками.

Моя ошибка заключалась в том, что поток пользовательского интерфейса создавал мой CBitmap, а затем обращался к объекту CBitmap из обоих потоков.

person Kieveli    schedule 16.10.2009
comment
Хех. Совершил ту же ошибку, перемещая код отрисовки в отдельный поток по точно таким же причинам. Получил несколько хороших ответов и ссылок на аналогичный вопрос, который может быть ценным; stackoverflow.com/questions/2287114/ - person SmacL; 22.04.2010
comment
Можете ли вы показать пример того, как вы хранили ручку? - person Vinz; 16.04.2015
comment
Именно MFC хранил дескриптор как часть реализации CBitmap. Если вы ищете что-то конкретное с дескрипторами или локальным хранилищем потока, задайте новый вопрос, чтобы привлечь больше людей! - person Kieveli; 17.04.2015