ASSERT се проваля при извикване на CDC SelectObject() - Какво мога да опитам?

Работя върху многонишково win32 MFC приложение. Изобразяваме карта и я показваме в панел в потребителския интерфейс заедно с изобразени по избор обекти отгоре. Изобразява се бавно (~800 ms), което се случва в нишката на потребителския интерфейс.

Опитвам се да преместя изобразяването в собствена нишка, така че менютата да останат бързи, докато другото изобразяване все още може да работи във фонов режим. Нишката 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 като валиден обект, когато се случи твърдението?   -  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. Ако има нещо конкретно, което търсите с Handles или локално хранилище в нишка, задайте нов въпрос, за да накарате повече хора да помогнат! - person Kieveli; 17.04.2015