Mit Thread Funktionen anderer Klassen aufrufen

Cappaja

Erfahrenes Mitglied
hallo,

ich starte den thread in der klasse CWiwoDlg wie folgt:
Code:
AfxBeginThread(ExecuteThread, pWiwoDlg, 0, THREAD_PRIORITY_NORMAL, 0, 0);

die methode ExecuteThread ist global und ruft variablen aus den klassen CWiwoDlg, sowie CGraph auf. wenn ich sie statisch deklariere erhalte ich fehlermeldungen. global sind die fehlermeldungen weg, doch sobald ich das programm durchdebugge und in die methode ExecuteThread() hineinspringe kommt eine fehlermeldung unabhängig vom code in der ersten befehlszeile: Zugriffsverletzung! wie kann ich also in einem thread eine funktion aus einer anderen klasse aufrufen?
oder sollte ich gar einen anderen weg gehen?
Code:
UINT ExecuteThread(LPVOID pParam)
{
	// Zeichnet die Daten in das Display
	while(((CWiwoDlg*)AfxGetMainWnd())->m_bThreadFlag)
    {
		if(((CWiwoDlg*)AfxGetMainWnd())->DSync)
		{	
			((CWiwoDlg*)AfxGetMainWnd())->DSync = false;

			if(((CWiwoDlg*)AfxGetMainWnd())->pDP.x1 != 0)
			{
				((CWiwoDlg*)AfxGetMainWnd())->m_pGraph->DataTransfer();
				Sleep(0);			// Setzt Thread auf ready!
			}
		}
    }
	return 0;
}

mfg cappaja
 

Cappaja

Erfahrenes Mitglied
habe das problem im ansatz gelöst. Ich habe die Threadfunktion in die Klasse CWiwoDlg gepackt und als static deklariert, anschließend caste ich pParam auf den klassenzeiger. so kann ich nun die parameter und funktionen ansprechen ohne einen fehler während der laufzeit zu erzeugen. jedoch läuft er jetzt zwar in die methode DataTransfer(), aber auch dort habe ich jetzt dasselbe problem wie zuvor, sodass ich diesen cast wohl auch dort überall anwenden muss? das sind viele methoden ineinander verschachtelt und der aufwand wäre riesig, hat wirklich niemand eine andere lösung parat?
Code:
UINT CWiwoDlg::ExecuteThread(LPVOID pParam)
{
	CWiwoDlg *pWiwoDlg = reinterpret_cast<CWiwoDlg*>(pParam);

	// Zeichnet die Daten in das Display
	while(pWiwoDlg->m_bThreadFlag)
    {
		if(pWiwoDlg->DSync)
		{	
			pWiwoDlg->DSync = false;

			if(pWiwoDlg->pDP.x1 != 0)
			{
				pWiwoDlg->m_pGraph->DataTransfer();
				Sleep(0);			// Setzt Thread auf ready!
			}
		}
    }
 

MCoder

Erfahrenes Mitglied
Hallo,

warum verwendest du einen Thread? Welche langlaufende Aktion wird da ausgeführt? Wenn es um eine regelmäßige Aktualisierung der GUI geht, würde es vielleicht auch ein Timer tun. Generell sind GUI-Zugriffe aus einem anderen Thread heraus immer etwas heikel. Alternativ könntest du im Thread eine Message an den Dialog schicken und so eine Aktualisierung anstoßen.

Gruß
MCoder
 

Cappaja

Erfahrenes Mitglied
hi mcoder,

die methode DataTransfer() holt die daten von der soundkarte in einen double-buffer. hier wird eigentlich noch ein memoryDC angelegt um die Daten in Bitmaps zu speichern und später mittels BitBlt() auf das Display wieder auszugeben. dazwischen wird je nach einstellungen eine fourier-transformation mit DoFT() vollzogen. Ich wüsste nicht wie ich das sonst anders lösen könnte. die töne die ins microphone kommen sollten so möglichst in echtzeit auf das display übertragen werden. der thread dauert immer genau so lange wie man in das microphone spricht oder solange eine matlab- oder wave-datei geöffnet und ausgegeben wird.

hier reiche ich momentan den pParam aus meiner thread funktione ExecuteThread() immer weiter durch, was nicht gerade optimal ist, zudem weiß ich noch nicht mal ob das überhaupt die gewünschte wirkung erzielt.

Code:
void CGraph::DataTransfer(LPVOID pParam)
{
	// DC zum Zeichnen anlegen
	CDC* pDC = m_pWnd->GetDC();

	if(((CWiwoDlg*)AfxGetMainWnd())->pDP.d_dom != 0)
	{
		DoFT(pParam);
		DrawData(pDC);
	}
	else
		DrawData(pDC);

	m_pWnd->ReleaseDC(pDC);
}
 
Zuletzt bearbeitet:

MCoder

Erfahrenes Mitglied
Hallo,

ich würde versuchen, das Holen und die Aufbereitung der Daten von der Ausgabe zu trennen. Also im Thread holst du die Daten und bereitest sie auf (FT) . Das Ergebnis schreibst du in eine Datenstruktur, die du im Dialog vorhältst oder vielleicht auch in eine globale Datenstruktur.
Das Zeichnen sollte ohnehin nur im WM_PAINT - Handler erfolgen, so dass nach Bereitstellung der Daten ein Invalidate() bzw. InvalidateRect() ausreicht, um ein Neuzeichen auszulösen.

Gruß
MCoder
 

Cappaja

Erfahrenes Mitglied
hallo,

ich habe bereits ein typedef struct für die globalen parameter, sowie ein typedef struct für die display daten. ich erhalte jetzt zumindest keine fehlermeldungen mehr. allerdings werden mir die daten nicht ins display gezeichnet, obwohl ich ein Invalidate() bzw. PaintGraph() ausführe.
ich weiß das es von vorteil ist die zeichenroutinen in den wm_paint handler zu packen, allerdings habe ich die grundstruktur des graphen aus einer fertigen klasse entnommen und diese einfach nur modifiziert. so lege ich halt immer einen CDC an und gebe ihn nach beendigung wieder frei, ist nicht optimal aber es funktioniert ohne einschränkung und das beste, beim aufruf von PaintGraph() flackert mein bildschirm in keinster weise wogegen bei Invalidate() unschöne weiße striche durchs display gleiten.

aber ich hätte da noch eine frage: woran merke ich das mein thread auch wirklich läuft und wann nicht? im taskmanager sollte doch eigentlich ein neuer prozess gestartet werden oder ist es bei diesem aufruf anders? denn bei mir steigt die hauptanwendung beim auslösen des threads auf 50% und der speicher schnellt von 5mb auf 18mb in die höhe, danach ist wieder normalbetrieb. ist das so richtig? sorry aber habe mit mfc threads noch nie wirklich etwas zu tun gehabt...

mfg cappaja
 

MCoder

Erfahrenes Mitglied
Hallo cappaja,

im Taskmanager siehst du diesen Thread nicht als eigenen Prozess. Das Ansteigen der Systemlast am Anfang ist ein Indiz dafür, dass "Sleep(0) "zunächst nicht ausgeführt wird.
Der Sleep-Befehl sollte besser bei jedem Durchlauf der Schleife ausgeführt werden:
C++:
while(pWiwoDlg->m_bThreadFlag)
{
    if(pWiwoDlg->DSync)
    {	
        // ...
    }
    
    Sleep(0);
}
Gruß
MCoder
 

Neue Beiträge