Klassen / Instanzen / Threads



  • Hallo,
    ich habe eine Kommunikationsklasse geschrieben, die per HTTP und HTTPs Daten von meinem Webserver abfragt. Das ganze basiert auf CURL, meine Klasse macht nur ein paar Spielereien drumherum.

    Wenn ich in der Kommunikationsklasse ne CCriticalSection einbaue, dann läuft das ganze zwar Fehlerfrei aber dafür erfolgen die Downloads nacheinander. Das MultiThreading ist also für die Katz. Wenn ich die CCriticalSection rausnehme, dann läuft es zwar wesentlich schneller (Downloads erfolgen parallel) aber dafür schmiert mir die Kiste mit ner AccessViolation ab.

    Wie krieg ich das Problem gelöst?

    Ich habe gedacht, dass wenn ich für jeden Download eine neue Instanz der Klasse nehme, ich eigentlich keine Probleme haben dürfte.

    Es sei noch angemerkt, dass Curl Threadsafe sein soll. Der Fehler liegt also bei mir.

    Hier mein Code:

    bool CtestAPPDlg::test_anything() 
    {
    	LARGE_INTEGER lStart, lEnd, lFreq;
    	QueryPerformanceFrequency(&lFreq);
    	QueryPerformanceCounter(&lStart);
    
    		int THREAD_COUNT = 10;
    
    		HANDLE		*HANDLE_ARR = new HANDLE[THREAD_COUNT];
    		CWinThread **CWIN_ARR = new CWinThread*[THREAD_COUNT];
    
    		for(int i=0; i<THREAD_COUNT; i++)
    		{
    			CWIN_ARR[i] = ::AfxBeginThread(test_worker, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
    			CWIN_ARR[i]->m_bAutoDelete = FALSE;
    			CWIN_ARR[i]->ResumeThread();
    
    			HANDLE_ARR[i] = CWIN_ARR[i]->m_hThread;
    		}
    
    		::WaitForMultipleObjects(THREAD_COUNT,HANDLE_ARR,TRUE,INFINITE);
    
    		for( i=0; i<THREAD_COUNT; i++ )
    		delete CWIN_ARR[i];
    
    		delete[] HANDLE_ARR;
    		delete[] CWIN_ARR;
    
    	QueryPerformanceCounter(&lEnd);
    	int ms=((lEnd.QuadPart - lStart.QuadPart) * 1000) / lFreq.QuadPart;
    
    	CString time_dif; 
    	double delta_t = (double)(ms)/1000;
    	time_dif.Format("\r\nBerechnet in: %.3f Sek.\r\n",delta_t);
    	TRACE(time_dif);
    	TRACE("FERTIG!!!\r\n");
    
    	return true;
    }
    
    UINT CtestAPPDlg::test_worker(LPVOID pParam)
    {
    		CtestAPPDlg* pDlg = (CtestAPPDlg*) pParam;		
    	//	pDlg->test_function();
    
    		CCommunicator neu;
    		CString quellcode;
    		neu.communicate("http://www.xyz.de/abc.php",quellcode,"");
    
    		return 1;
    }
    
    bool CtestAPPDlg::test_function() 
    {
    	CCommunicator neu;
    	CString quellcode;
    	return neu.communicate("http://www.xyz.de/abc.php",quellcode,"");
    }
    


  • wo passiert die access violation?



  • ASSERT_VALID fails with illegal vtable pointer.
    Nicht abgefangene Ausnahme in xyz.exe (KERNEL32.DLL): 0xC0000005: Access Violation.
    ASSERT_VALID fails with illegal vtable pointer.
    Second Chance Assertion Failed: File thrdcore.cpp, Line 113
    Nicht abgefangene Ausnahme in xyz.exe (KERNEL32.DLL): 0xC0000005: Access Violation.

    Komischer Weise läuft er aber erst durch.

    [...]
    Thread 0xDB0 wurde mit Code 1 (0x1) beendet.
    Thread 0x11B0 wurde mit Code 1 (0x1) beendet.
    Thread 0x1168 wurde mit Code 0 (0x0) beendet.
    Thread 0xF60 wurde mit Code 0 (0x0) beendet.
    Thread 0x1624 wurde mit Code 0 (0x0) beendet.
    Thread 0xE50 wurde mit Code 1 (0x1) beendet.
    Thread 0x1338 wurde mit Code 0 (0x0) beendet.
    Thread 0xB28 wurde mit Code 1 (0x1) beendet.
    Thread 0xAC0 wurde mit Code 0 (0x0) beendet.
    Thread 0x180 wurde mit Code 0 (0x0) beendet.

    Alle Threads gestartet. WARTE JETZT!
    Berechnet in: 20.419 Sek.
    FERTIG!!!

    [Hier kommt dann der Teil, der oben steht: ASSERT_VALID fails ...]



  • Kann es sein, dass der eigentliche Fehler im Multithreading liegt?

    Wenn ich:
    /*
    for( i=0; i<THREAD_COUNT; i++ )
    delete cThreads[i];

    delete[] hThreads;
    delete[] cThreads;
    */

    auskommmentiere, dann kriege ich zwar die memory leaks aber dafür kriege ich keine access violations.



  • Debug mal bitte durch und zeig mir die genaue Zeile in der es fehl schlägt. Für mich sieht es so aus, als überschreibst du irgendwo Speicher der dir nciht gehört



  • Peinlicher Weise weiß ich nicht genau, wie du das mit dem "durch debguggen" meinst. Ich glaube, dass ich mir mal euer Tutorial zu dem Thema durchlesen muss.

    Durch rumprobieren, bin ich aber auch schon etwas weiter.

    Wenn ich das Folgende mache, dann kriege ich auch keine violation:

    // Alle Threads wurden gestartet. Jetzt wird gewartet
    TRACE("\r\nAlle Threads gestartet. WARTE JETZT!");
    ::WaitForMultipleObjects(THREAD_COUNT,hThreads,TRUE,INFINITE);

    Sleep(5000);

    // Auräumen
    // Threads manuell löschen, da m_bAutoDelete=FALSE
    for( i=0; i<THREAD_COUNT; i++ )
    delete cThreads[i];

    delete[] hThreads;
    delete[] cThreads;

    Scheinbar wartet WaitForMultipleObjects nicht lange genug und so werden die Arrays schon gelöscht, bevor alle Threads beendet sind. Wenn auf die Handles dann zugegriffen wird kommt die violation.

    Aber wie löse ich das Problem?



  • Hallo,
    ich debugge das Prog jetzt gerade.
    Ich teste es mit 30 Threads.

    for( i=0; i<THREAD_COUNT; i++ )
    delete cThreads[i];

    delete[] hThreads;
    delete[] cThreads;

    In diesem Abschnitt sieht noch alles okay aus aber dann in Zeile

    QueryPerformanceCounter(&lEnd);

    Steht in der Ansicht der Variablen:

    cThreads
    - oxfeeefeee {CWinThread h=??? proc=???}
    + CCmdTarget {CCmdTarget}
    - p_pMainWnd | CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    - p_pActiveWnd | CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    - p_pAutoDelete | CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    - p_hThread | CXX0030: Fehler: Ausdruck kann nicht ausgewertet werden
    [...]
    Bei allen Einträgen steht "Fehler: Ausdruck kann nicht ausgewertet werden"

    Das ist ja auch eigentlich verständlich, weil ich zuvor
    for( i=0; i<THREAD_COUNT; i++ )
    delete cThreads[i];
    verwendet habe.

    Muss ich cThreads anders löschen?



  • probiers mal so:

    CWinThread *CWIN_ARR = new CWinThread[THREAD_COUNT];
    


  • cThreads[i] = ::AfxBeginThread(test_worker,this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);

    error C2582: Die Funktion für Operator '*' ist in '<unbekannt>' nicht verfügbar

    Wie muss ich die Zeile ändern?



  • sorry, mein Fehler, deins war richtig. Hab dann grad auch keine Ahnung mehr.



  • Okay,
    ich habe jetzt weiter zum Thema Debuggen gelesen und kann dir neue Infos geben.

    Im Callstack steht:
    feeefeee()
    _AfxThreadEntry(void * 0x0012f05c) line 112 + 13 bytes
    _threadstartex(void * 0x00b28170) line 227 + 13 bytes
    KERNEL32! 7c80b683()

    Klicke ich auf feeefeee(), dann zeigt er im Dissamblierungs-Fenster:
    FEEEFEEE ???

    Hilft das irgendwie?
    Der Fehler muss irgendwo im Löschen der Arrays liegen. Wenn ich zwischen WaitForMultipleObjects und dem Löschen nen Sleep(5000) packe, dann kriege ich ja keine access violation.

    Vielen Dank für die Hilfe!


Anmelden zum Antworten