Hilfe:Mit thread auf member-variable in Doc-klasse zugreifen->Absturz
-
Hallo,
Ich schlage mich schon seit tagen mit einem problem rum und finde keine Lösung.Ich greife imit einem thread auf ein CImage objekt zu und zeichne dieses gleichzeitig in einem dialogfenster und mein prog stürzt regelmäsig ab:
Ich habe in der Doc-klasse eine menbervariable
CImage m_bmp;die ich im Konstruktor erzeuge
m_bmp.Create(800,800,24);Dann hab ich einen Thread, in dessen funktion auf dieses image zugegriffen wird,
z.B. so:UINT __cdecl Cradar_02App::Thread708Func(LPVOID pParam){ ThreadStruct* temp=(ThreadStruct* )pParam; Cradar_02Doc* pDoc=(Cradar_02Doc*)temp->pDoc; while(true){ pDoc->m_pbmp.SetPixel(100,100,RGB(222,222,222)); } return 0; }Ausserdem zeichne ich das image in einem dialog:
void CPaintDlg::OnPaint(){ Cradar_02Doc* pDoc = dynamic_cast<Cradar_02Doc*>(((CMainFrame*)AfxGetMainWnd())->GetActiveDocument()); ASSERT(pDoc); // Gerätekontext zum Zeichnen CPaintDC dc(this); CPaintDC* pdc=&dc; CRect rRect; GetClientRect(rRect); rRect.NormalizeRect(); pDoc->m_pbmp.Draw(pdc->m_hDC, rRect); DeleteObject(&pdc); DeleteObject(&rRect); }Wenn jetzt der thread läuft und man das fenster schnell hin und her bewegt (sodass oft onpaint aufgerufen wird) stürzt das programm durch einen ASSERT in ReleaseDC() ab:
Der Debugger zeigt mir dann an:
inline void CImage::ReleaseDC() const throw() { HBITMAP hBitmap; ATLASSUME( m_hDC != NULL ); m_nDCRefCount--; if( m_nDCRefCount == 0 ) { hBitmap = HBITMAP( ::SelectObject( m_hDC, m_hOldBitmap ) ); -> ATLASSERT( hBitmap == m_hBitmap ); s_cache.ReleaseDC( m_hDC ); m_hDC = NULL; } }hBitmap ist auf 0x00000000 ?!?
Vielleicht weiss ja jemand, was ich hier verbocke.
-
CImage ist nicht threadsicher!
Intern werden Referenz Zähler benutzt für einen temporären DC. Dazu wird aber m_nDCRefCount++; und kein InterlockedIncrement verwendet.Es wundert nicht, dass dies aus zwei Threads heraus und einer multiporzessor Maschine zum Crash führt...
Verwende eine CrticalSection um die Nutzung auf einen Thread zu einer Zeit zu begrenzen.
-
Danke,
ich hab also eine klasse CImageThreadsicher von CImage abgeleitet und in dieser die methoden setpixel und draw überschrieben und arbeite dann nur noch mit dem CImagethreadsicher objekt.[cpp] class CImageThreadSicher : public CImage { public: CImageThreadSicher(void); public: ~CImageThreadSicher(void); private: CCriticalSection m_CS; public: void SetPixel(int x,int y,COLORREF color); void Draw(HDC hDestDC,const RECT& rectDest); };void CImageThreadSicher::SetPixel(int x,int y,COLORREF color){ m_CS.Lock(); CImage::SetPixel(x,y,color); m_CS.Unlock(); }Es scheint zu funktionieren
