Hilfe bei Threads!!!



  • Hallo zusammen,

    ich brauche Hilfe beim Erstellen und Anwenden von Threads!
    Ich möchte einen Analogen InputPort solange auslesen, bis ein Button grdrückt wird.

    Ich habe folgende Klassen:
    CAnalogIn: öffnet Port und liest ein, berechnet
    CDlgAnalogIn: soll die die Berechneten Werte ausgeben.

    Ich habe eine Klasse MyThread, abgeleitet von CWinThread erstellt.

    Jetzt muss ich doch mit AfxBeginThread den Thread starten oder?

    Ich hab mir das Beispiel aus der FAQ angeschaut und versucht so einzubauen, aber ich bekomm Fehlermeldungen:
    error C2027: use of undefined type 'CMyThread'

    obwohl ich es genau wie in der FAQ gemacht habe.

    Kann mir jemand ein Beispiel für Threads geben oder einen Lösungsvorschlag machen?

    Weiß nicht mehr weiter... 😞



  • monne81 schrieb:

    Ich habe eine Klasse MyThread, abgeleitet von CWinThread erstellt.

    Ich hab mir das Beispiel aus der FAQ angeschaut und versucht so einzubauen, aber ich bekomm Fehlermeldungen:
    error C2027: use of undefined type 'CMyThread'

    Wenn die Klasse "MyThread" heißt, kannst du sie nicht per "CMyThread" ansprechen 😉



  • Ist nur ein Tipp Fehler, die Klasse heißt natürlich CMyThread. Sorry.

    Ich hab jetzt so lange rumprobiert und bekomme jetzt nur noch diese Fehlermeldungen:

    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(66) : error C2039: 'classCMyThread' : is not a member of 'CMyThread'
            c:\dokumente und einstellungen\e-labor\eigene dateien\projekt sis\dolmetscher\mythread.h(14) : see declaration of 'CMyThread'
    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(66) : error C2065: 'classCMyThread' : undeclared identifier
    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(67) : error C2039: 'SetOwner' : is not a member of 'CMyThread'
            c:\dokumente und einstellungen\e-labor\eigene dateien\projekt sis\dolmetscher\mythread.h(14) : see declaration of 'CMyThread'
    

    So sieht mein Code aus:
    CDlgAnalogIn::OnInitDialog

    m_xDisplayThread = (CMyThread*)AfxBeginThread(RUNTIME_CLASS(CMyThread), NULL, 0, CREATE_SUSPENDED);
    	m_xDisplayThread->SetOwner(this);
    	m_xDisplayThread->ResumeThread();
    

    So meine Klassendefinitionen:

    class CDlgAnalogIn : public CDialog
    {
    // Construction
    public:
    	CBrush m_brush_white, m_brush_green;
    	CDlgAnalogIn(CWnd* pParent = NULL);   // standard constructor
    	//class CMyThread;
    
    	CMyThread* m_xDisplayThread;
    .
    .
    .
    
    #include "DlgAnalogIn.h"
    
    class CMyThread : public CWinThread  
    {
    public:
    	CMyThread();
    	virtual ~CMyThread();
    	virtual int Run();
    	class CDlgAnalogIn;
    	CDlgAnalogIn *m_dialogvar;
    	CDlgAnalogIn *m_pOwner;
    //	void SetOwner(CDlgAnalogIn* pOwner) { m_pOwner = pOwner; };
    
    };
    

    Ich möchte den Thread von InitDialog aus starten und ihn beenden so bald ein Button Stop gedrückt wurde. Wie stoppe ich den Thread?
    waitforSingleObject?



  • monne81 schrieb:

    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(66) : error C2039: 'classCMyThread' : is not a member of 'CMyThread'
            c:\dokumente und einstellungen\e-labor\eigene dateien\projekt sis\dolmetscher\mythread.h(14) : see declaration of 'CMyThread'
    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(66) : error C2065: 'classCMyThread' : undeclared identifier
    

    Setz' mal ein DECLARE_DYNAMIC(CMyThread) in die Deklaration von CMyThread (und IMPLEMENT_DYNAMIC(CMyThread,CWinThread) in die Thread.cpp

    C:\Dokumente und Einstellungen\E-Labor\Eigene Dateien\Projekt SIS\Dolmetscher\DlgAnalogIn.cpp(67) : error C2039: 'SetOwner' : is not a member of 'CMyThread'
            c:\dokumente und einstellungen\e-labor\eigene dateien\projekt sis\dolmetscher\mythread.h(14) : see declaration of 'CMyThread'
    

    Klar, wenn du die CMyThread::SetOwner()-Methode auskommentiert hast 🙂



  • SCh...e schon wieder ein blöder Fehler, das auskommentierte ist bereits wieder weg!!!

    Jetzt hab ich nur noch einen Fehler:

    rror C2664: 'SetOwner' : cannot convert parameter 1 from 'class CDlgAnalogIn *const ' to 'class CMyThread::CDlgAnalogIn *'
    

    der Parameter bei SetOwner passt nicht!

    #include "DlgAnalogIn.h"
    
    class CMyThread : public CWinThread  
    {
    public:
    	CMyThread();
    	virtual ~CMyThread();
    	virtual int Run();
    	class CDlgAnalogIn;
    	CDlgAnalogIn *m_dialogvar;
    	CDlgAnalogIn *m_pOwner;
    	void SetOwner(CDlgAnalogIn* pOwner) { m_pOwner = pOwner; };
    	DECLARE_DYNAMIC(CMyThread);
    
    };
    
    m_xDisplayThread->SetOwner(this);
    

    Und wie startet der Thread ?????????????



  • monne81 schrieb:

    SCh...e schon wieder ein blöder Fehler, das auskommentierte ist bereits wieder weg!!!

    Jetzt hab ich nur noch einen Fehler:

    rror C2664: 'SetOwner' : cannot convert parameter 1 from 'class CDlgAnalogIn *const ' to 'class CMyThread::CDlgAnalogIn *'
    

    der Parameter bei SetOwner passt nicht!

    "klassischer" Namenskonflikt wegen Überaktivität - lösch mal die Zeile "class CDlgAnalogIn;" aus der Deklaration von CMyThread, damit definierst du eine neue Klasse, die mit deiner Dialogklasse nichts zu tun hat (und die außerdem völlig überflüssig ist).

    Und wie startet der Thread ?

    Der Thread wird mit deinem obigen AfxBeginThread-Aufruf gestartet und erstmal auf Eis gelegt und mit ResumeThread() dann endgültig angestartet.

    PS: Für einen Worker-Thread solltest du dir eher eine Thread-Funktion anlegen und verwenden statt einer CWinThread-Klasse (letztere ist für Interface-Aufgaben gedacht).



  • beim Builden kriege jetzt folgende Fehler Meldung:

    MyThread.obj : error LNK2001: unresolved external symbol "public: virtual int __cdecl CMyThread::Run(void)" (?Run@CMyThread@@UAAHXZ)
    ARMV4IDbg/Dolmetscher.exe : fatal error LNK1120: 1 unresolved externals
    Error executing link.exe.
    

    externals heisst wohl, das er einen Header nicht findet.

    😡 Ich hasse Threads!!!!



  • Nein: Unresolved external heißt, daß er zwar den Header gefunden hat, aber nicht die Quelldatei, in der du die Run()-Methode implementiert hast.



  • Richtig... also auf Deutsch... du hast deine CMyThread::Run(void) nur declariert aber nicht definiert 😃



  • monne81 schrieb:

    😡 Ich hasse Threads!!!!

    es muss heissen: Ich hasse MFC!!!!



  • net schrieb:

    monne81 schrieb:

    😡 Ich hasse Threads!!!!

    es muss heissen: Ich hasse MFC!!!!

    😃 👍



  • Morggäääännn,

    Nachdem ich heute nacht nur von Threads und grobpixeligen Frauen geträumt habe,
    ist mir die ganze Sache etwas klarer geworden. Jedoch noch nicht so klar wie eisgekühlter Korn an einem Sonntagmorgen. 😉

    für meine Anwendung brauche ich erstmal einen Worker Thread, oder?

    ich habe mir jetzt eine Threadfunktion gebaut:

    UINT CDlgAnalogIn::thread_function(LPVOID pParam)
    {
       CDlgAnalogIn* pDlg = (CDlgAnalogIn*) pParam;
       pDlg->SetValue();
    
        return 0;
    }
    

    diese rufe ich im Dialog auf:

    m_xDisplayThread = (CMyThread*)AfxBeginThread(thread_function, this);
    

    sprich ich kann mir die ganze Klasse CMyThread sparen.

    Leider bekomme ich eine Assertion Failed Message!!!!!

    Jetzt noch eine grundlegende Frage:

    wenn ich den Thread (userinterface Thread??) über eine Klasse definiere und so aufrufe:

    CMyThread* m_xDisplayThread;
    	//m_nTimer=SetTimer(1,200,0);
    
    	m_xDisplayThread = (CMyThread*)AfxBeginThread(RUNTIME_CLASS(CMyThread), NULL, 0, CREATE_SUSPENDED);
    //	m_xDisplayThread = (CMyThread*)AfxBeginThread(thread_function, this);
    
    	m_xDisplayThread->SetOwner((CMyThread::CDlgAnalogIn*)this);
    	m_xDisplayThread->ResumeThread();
    

    wird der Thread ja über ResumeThread() gestartet

    In welche Funktion springt mein Thread dann? bzw. ich habe in meiner Threadklasse eine Methode, die ausgeführt werden soll, nur wie rufe ich die auf??? 😕



  • Du brauchst entweder einen Worker-Thread, der nach dem Start still vor sich arbeitet und eventuell Werte an seinen Chef zurückgibt (über den mitgelieferten Parameter) oder einen Interface-Thread, der ein Fenster erstellt und darüber mit dem Nutzer kommunizieren kann.

    In deinem Beispiel benötigst du wohl doch einen Interface-Thread - allerdings mußt du ihn vom Hauptprogramm (CDlgAnalog oder CAnalogApp) aus starten und dann innerhalb der InitInstance()-Methode deinen Dialog anlegen.



  • Hi,

    genügt nicht ein Worker Thread? der thread soll ja nur im Hintergrund die Werte vom Analog Input einlesen einen Mittelwert bilden und diesen Mittelwert dann an den Dialog CDlgAnalogIn senden.

    Leider bekomm ich immer noch die Assertion Failed und hab keine Ahnung wieso!

    wenn ich step by step durchgehe liest er einmel den Port aus zeigt die Werte an und beim 2ten Mal Berechnen (Aufruf von SetValue()) kommt die Assertion!
    😕



  • Steht da nicht noch eine Zusatzinfo in der Assertion Failed Meldung? (Dateiname, Zeilennummer)



  • monne81 schrieb:

    genügt nicht ein Worker Thread? der thread soll ja nur im Hintergrund die Werte vom Analog Input einlesen einen Mittelwert bilden und diesen Mittelwert dann an den Dialog CDlgAnalogIn senden.

    Achso, das geht natürlich auch. In dem Fall dürfte dein Problem wohl in der SetValue()-Funktion zu finden sein: Der Dialog (also was du auf dem Monitor siehst) darf nur von dem Thread direkt angesprochen werden, der ihn erzeugt hat (und das ist der Hauptthread).

    Lösung: SetValue() speichert nur intern ab, was sich geändert hat und signalisiert dann dem Hauptthread, daß etwas passiert ist:

    void CDlgAnalogIn::SetValue(int data)
    {
      m_data = data;
      PostMessage(WM_DATACHANGED);
    }
    
    LRESULT CGldAnalogIn::OnDatachanged(WPARAM w,LPARAM l)
    {
      //stelle den Wert von m_data im Dialog dar
    }
    

    (WM_DATACHANGED ist eine selbstdefinierte Nachricht, OnDatachanged die zugehörige Behandlungsroutine)



  • Also meine Assertion Failed sagt mir folgendes:

    Dolmetscher:File
    wincore.cpp, Line1051

    @CStoll

    Verstehe ich das richtig, dass ich mit meiner thread_function den Dialog nicht ansprechen darf, weil thread_function den Dailog nicht erstellt hat????

    ich probiers mal aus, ich glaub ich habs...

    Noch eine Frage:

    ich glaub die Werte werden ziemlich häufig erneuert (Signal am Port ist Audiosignal) kann das zu Problemen führen? Die WM wir dann ja ziemlich häufig aufgerufen....



  • monne81 schrieb:

    Also meine Assertion Failed sagt mir folgendes:

    Dolmetscher:File
    wincore.cpp, Line1051

    Dann klick mal auf "Abbrechen" (das setzt den Debugger an die Stelle, wo der Fehler aufgetreten ist) und wandere ein paar Stufen im Call-Stack nach oben.

    Verstehe ich das richtig, dass ich mit meiner thread_function den Dialog nicht ansprechen darf, weil thread_function den Dailog nicht erstellt hat????

    Ja, so sieht's aus: die Funktion darf zwar interne Daten umstellen, aber nicht direkt (oder indirekt) auf die Dialogelemente zugreifen - deshalb der Umweg über PostMessage (der MessageHandler wird bei nächster Gelegenheit im Rahmen der Nachrichtenschleife aufgerufen, und die sitzt im richtigen Thread).



  • tatat....

    Danke!!! funktioniert alles prima....

    bis auf eine "Kleinigkeit":

    Wenn ich den Dialog beende soll der Thread auch beendet werden, ich mach dies mit

    void CDlgAnalogIn::OnOK() 
    {
    	b_running=false;
    	delete m_xDisplayThread;
    
    	CDialog::OnOK();
    }
    

    dann bekomm ich aber wieder eine Assertion Failed!

    Darf ich den Thread so beenden?



  • monne81 schrieb:

    Darf ich den Thread so beenden?

    Kurz: Nein.

    Setz' besser eine Variable, die der Thread wiederfindet und lass ihn sich dann selber beenden (AfxEndThread()).

    PS: Weitere Informationen in der MSDN


Anmelden zum Antworten