RichEdit nach der Benutzung wieder freigeben?



  • Hallo,

    Ich habe eine Work-Klasse, die einmal eine Consolen-Klasse und einmal einen eig. Thread hat. Die Console verwaltet eine richedit komponent, und sobal CWork erstellt wird, wird ebenfalls die Konsole und der Thread gestartet.

    Die Work-Klasse kann 5-20x exisitieren. Je nachdem was zu tun ist. Die Konsole schreibst dabei alles mit was man ihr übergibt.

    PROBLEM:

    Wenn ich nun, das Programm beenden will, warte ich mit WaitForsingleObject auf das Ende aller Threads.
    Doch das gibt Probleme, die Threads scheinen einfach aufzuhören zu arbeiten - nach 20sec geht es manchmal wieder weiter. Via BOOL Variable prüfe ich ob ein Shutdown kommt.

    DIE LÖSUNG?

    Wenn ich jedoch die RichEdit komponente leer lasse funktioniert alles wunderbar, alles wird perfekt beendet. sobald ich text in die Richedit komponente einfüge gibt es die Fehler.

    Bin Ziemlich verwirrt. Kann ich irgendwie ein richedit controle freigeben?
    🙄 🙄 🙄 🙄



  • Eine Konsole mit Richedit-Feld? Oder meinst du eher einen Dialog? (zur Erklärung: Mit "Konsole" wird normalerweise ein DOS-Fenster bezeichnet - das hat keine RichEdits)

    Ansonstens solltest du ganz einfach kontrollieren, wo genau der Thread sich aufgehängt hat.


  • Mod

    Wer erzeugt die Rich Edit Controls?
    Windows sind Thread afin. Sendest Du eine Nachricht an ein Fenster in einem anderen Thread, dann muss dieser Thread eine Message Queue haben.

    Es ist sicherlich kein Problem im Debugger Break All anzuklicken und zu sehen was die einzelnen Threads in dem kritischen Moment machen. (Doppelklick auf die jeweilgen Threads im Thread Window).



  • Hi, jep klar ist das ein Dialog mit einer Richedit kompo. 👍

    Also die Console Klassen werden im Main-Thread erstellt. Somit ist die Haut-Queue dafür verantwortlich - das klappt auch alles wunderbar und perfekt bis zum Shutdown.

    "Es ist sicherlich kein Problem im Debugger Break All anzuklicken und zu sehen was di"

    Öhm wir mach ich das?



  • Freak33 schrieb:

    Also die Console Klassen werden im Main-Thread erstellt. Somit ist die Haut-Queue dafür verantwortlich - das klappt auch alles wunderbar und perfekt bis zum Shutdown.

    Dann ist auch der Haupt-Thread für die Ausgaben verantwortlich (alles andere bereitet Probleme). Aber um ein Sprichwort abzuwandeln - "Ein Code sagt mehr als tausend Worte" 😉


  • Mod

    Freak33 schrieb:

    "Es ist sicherlich kein Problem im Debugger Break All anzuklicken und zu sehen was di"

    Öhm wir mach ich das?

    Debugger laufen lassen. Bis Problem aufttaucht. Dann gibt es in der Button-Leiste den Schalter Break-All. Anklicken. Debug-Thread Window öffnen und die Threads ansehen, was sie tun.



  • Ok, hab ich jetzt gemacht. Hier die laufenden Threads:

    >	2948	__tmainCRTStartup	__tmainCRTStartup	Normal	1
     	436	Win32 Thread	        7c91eb94	        Highest	1
     	2900	Win32 Thread	        7c91eb94	        Normal	0
     	3212	CTable::Run	        7c91eb94	        Normal	1
     	4088	CTable::Run	        7c91eb94	        Normal	1
     	3084	CTable::Run	        7c91eb94 	        Normal	1
     	380				                        0
    

    Und an folgender Stelle bleibt er hängen:

    void CTableManager::Release()
    {
    	for( int table=0; table < m_aTables.size(); table++ )
    	{
    >		m_aTables.at(table)->Stop();  // HIER
    	}
    }
    

    Die Methode "Stop" schaue folgendermaßen aus:

    BOOL CTable::Stop()
    {
    	if( m_bInit )
    	{
    		m_bStop = TRUE;
    		WaitForSingleObject( m_hRunThread, 10000 );
    		CloseHandle( m_hRunThread );
    
    		return TRUE;
    	}
    	return FALSE;
    }
    

    So, WaitForSingleObject() scheint wohl die Ursache zu sein. Wenn ich die Funktion entferne, werden alle Threads durch den Primär Thread zum Ende gezwungen.

    Hier mal ein Ausschitt aus der CTable::Run

    DWORD WINAPI CTable::Run( LPVOID lpParam )
    {
    
    	// pointer
    	CTable *pT = (CTable*)lpParam;
    
    	// do some updates
    	while( !pT->m_bStop )
    	{
                    // Wenn diese Zeile weg ist, klappt alles wunderbar
    		pT->m_cConsole.AddLine( "Update" );
    
    		Sleep(0);
    	}
    
    	OutputDebugString( "\n Thread Finished" );
    
    	return 2;
    }
    


  • Achja, die Funktion AddLine schaut folgendermaßen aus:

    void CConsole::AddLine( char *msg )
    {
    	if( m_hWnd != NULL )
    	{
    		int length = (int)SendMessage( m_hWndConsole, WM_GETTEXTLENGTH, 0, 0 );
    		SendMessage( m_hWndConsole, EM_SETSEL, length, length );
    		SendMessage( m_hWndConsole, EM_REPLACESEL, TRUE, (LPARAM)msg );
    	}
    
    }
    


  • Ok, es gibt auf jedenfall eine Verbindung zwischen den RichEdit funktionen (egal was passiert Ob man texte einfügt ob nur die Länge des Textes abgefragt wird), wenn ich das in einem Thread aufrufe und parallel WaitForSingleObject aufrufe gibt es Probleme.

    Wobei ich nicht glaube, dass das Problem bei WaitSingleObject liegt - Hier wird nur gewartet bis der Thread beendet wird (Was er nicht tut).

    Es muss ein Problem sein, was mit Thread und einer RichEdit Komponente zu tun hat.

    Jemand eine Idee?? 🙄



  • Neue Theorie:

    Könnte es sein, dass durch WaitForSingleObject() Die RichEditKomponente keine Nachrichten mehr verarbeiten kann (da dadurch der Primär-Thread mit der Msg-Queue lahmgelegt ist)?


  • Mod

    Genau das passiert! Du wartest auf den Thread und nun können keine Nachrichten mehr empfangen werden. Verwende MsgWaitForMutipleObjects und lass die Message Loop weiter laufen.
    Es ist gar nicht gut, dass das RTF Control in einem anderen Thread liegt!
    Warum machst Du das überhaupt?



  • Also ich hab das mal mit "MsgWaitForMultipleObjects" ausprobiert - war aber kein Erfolg.

    MsgWaitForMultipleObjects( 1, &m_hRunThread, TRUE, INFINITE, QS_ALLINPUT );
    CloseHandle( m_hRunThread );
    

    Mit folgendem Code klappt alles wunderbar:

    while( m_bThreadRunning )
    {
    	CBaseApp::GetApp()->ProcessMessageQueue();
    	Sleep(0);
    }
    

    Mit CBaseApp::ProcessMessageQueue

    void CBaseApp::ProcessMessageQueue()
    {
    	MSG msg;
    	if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
    	{
    		TranslateMessage(&msg); 
    		DispatchMessage(&msg); 
    	}
    }
    

    Warum machst Du das überhaupt?

    Das ist automatisch so, da die Klasse CConsole im Primär-Thread erstellt wird und damit auch zu dieser Queue "gehört"!!
    Wie könnte man das denn anders regeln? -> Somit hätte jeder Thread eine eig. Queue?


  • Mod

    1. MsgWaitForMultipleObjects returniert auch, wenn eine Nachriht in der Message Queue drin ist! Dann muss also auch die Nachrichtenschleife laufen. Diese Funktion behandelt keine Nachrichten!

    2. Ich verstehe immer noch nicht was CConsole ist! Das ist das RTF Control?

    Wenn Du also Nachrichten aus den anderen Threads bekommst, dann musst Du auch bis zum letzten Moment auf Nachrichten reagieren.
    Also
    MsgWaitForMultipleObjects durchführen.
    Wenn eine Nachricht vorhanden ist, diese bearbeiten.
    Solange das weiter machen, bis alle Threads terminiert haben.


  • Mod

    BTW:
    Dein Code:

    int length = (int)SendMessage( m_hWndConsole, WM_GETTEXTLENGTH, 0, 0 ); 
         SendMessage( m_hWndConsole, EM_SETSEL, length, length ); 
         SendMessage( m_hWndConsole, EM_REPLACESEL, TRUE, (LPARAM)msg );
    

    Ist nicht threadsicher. Was passiert wenn zwei Threads gleichzeitig hier die Nachrichten "durcheinander" senden. Also nachdem du WM_GETETXTLENGTH ausgeführt hast ein anderer Thread die Länge verändert.

    Du solltest Dir einen anderen Mechanismus für die Nachrichten ausdenken.


Anmelden zum Antworten