::PeekMessage im Thread abarbeiten



  • Guten Morgen zusammen

    Zu früher Stunde schon eine kleine schwierige Aufgabe *gg*

    Ich will meine ::PeekMessage in einem Thread abarbeiten, das funktioniert aber nicht so richtig.

    Hintergrund der Sache ist, dass ich vor Threadstart einen Befehl sende, wo ich genau weiß, dass darauf direkt eine Message zurück kommt, nur leider kann ich den genauen Zeitpunkt nicht bestimmen.

    Eigentlich könnte ich ja auch mit GetMessage() arbeiten, ich will aber nicht, dass meine Anwendung während dessen "einfriert". Desshalb die Wahl auf PeekMessage im Thread.

    Problem: Thread startet aber er fängt mir die Nachricht nicht ab. Code funktioniert aber so, weil ich es erst ganz dreckig mit einer Endloschleife getestet habe.

    Hier der Code:

    UINT CTestDlg::Abfrage(void *pParam)
    {
    	CTestDlg* lpouterThis = (CTestDlg*) pParam;
    	::WaitForSingleObject(lpouterThis->g_eventStart,INFINITE);
    	do
    	{
    		while (::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
    		{
    			if (!AfxGetApp()->PumpMessage())
    				return 0;
    		}
    		if ( lpouterThis->abbruch )
    			lpouterThis->g_eventKill.SetEvent();
    	}
    	while(::WaitForSingleObject(lpouterThis->g_eventKill,0) != WAIT_OBJECT_0);
    	return 0;
    }
    

    Thread wird folgendermaßen gestartet:

    void CTestDlg::OnBnClick()
    {
         ....
         this->thread = AfxBeginThread(Abfrage,this);   //thread = CWinThread als Member in Header
         this->g_eventStart.SetEvent();   //g_eventStart = CEvent als Member im Header so wie g_eventKill
    }
    


  • Ich verstehe den Sinn dieses Threads überhaupt nicht. Warum musst du in diesem Thread Nachrichten verarbeiten? Das macht doch dein GUI-Thread schon. Man startet doch üblicherweise Threads, damit die Nachrichtenschleife nicht blockiert wird.

    Diese Nachricht, auf die du wartest, wird schon irgendwann in der Nachrichtenschleife deines UI-Threads aufschlagen. Da kannst du dann darauf reagieren.

    Und warum benutzt du zum Signalisieren von außen die Variable abbruch, zum Beenden deiner lokalen Schleife aber ein Event, das du in der Schleife selbst setzt? Warum setzt du nicht gleich von außen das Event?

    Das Event zum Starten brauchst du auch nicht. Starte den Thread mit CREATE_SUSPENDED und lass ihn mit ResumeThread loslaufen, wenn es losgehen soll.



  • ja, du hast vollkommen recht

    aber:

    ich muss dort auf eine Nachricht warten, die dann gesendet wird, wenn ich vom COM Port Daten empfange.

    diese daten tue ich aber erst empfangen, nachdem ich was geschrieben habe.

    Example:

    void CTestDlg::OnButtonClick()
    {
       SchreibeAufCom1Befehl1();
       WarteAufAntwortVonCom1();   //ob OK oder ERROR
       SchreibeAufCom1Befehl2();
       WarteAufAntwortVonCom1();   //ob OK oder ERROR
       ...
    }
    

    Ich muss damit halt ne Nachricht abfangen, die gesendet wird, wenn ich die Antwort von der COM bekomme.

    Deswegen dieses Construct.


  • Mod

    Ab dazu benötigt man doch keine Nachrichten um mit Threads kommunizieren zu können, nimm ein Event, das ist viel effektiver und kostet vor allem keine Rechnerzeit wie Dein Code, der 100% Prozessozeit frisst!

    Was ist das Problem, dass Du zu solch einem Konstrukt greifst?
    Lagere den COM-I/O in einen Thread aus, kontrolliere den Thread vom Mainthread aus.



  • Martin Richter schrieb:

    Was ist das Problem, dass Du zu solch einem Konstrukt greifst?

    Ich vermute, das hier:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-170161.html

    @MSS-Software:
    Ich glaube, der einzige Grund, warum du glaubst, in OnButtonClick auf die Antwort warten zu müssen, ist der, dass du die Reihenfolge deiner Befehle nicht anders umsetzen kannst. So wird das aber nichts.

    Bau dir irgendwo einen "Befehlszähler" ein, z.B. in CTestDlg. Schick den ersten Befehl ab, und immer, wenn du eine Antwort bekommst (Nachricht), zählst du den Befehlszähler hoch und schickst den nächsten Befehl. So brauchst du auf nichts zu warten.



  • noch was zu den befehlen:
    vor dem abschicken des befehls ein 'PurgeComm' aufrufen, damit überbleibsel im empfangsbuffer gelöscht werden.
    das warten auf "OK\r\n" usw. mit einem time-out versehen, damit, falls nichts oder was anderes kommt, der thread nicht hängen bleibt.
    🙂



  • ja, MFK

    ich kann meine Reihenfolge der Befehle leider nicht anders umsetzen. Das ist der Grund, weswegen ich sowas gemacht habe *Gg*

    Die Lösung, die du geschrieben hast, hatte ich auch ganz am Anfang implementiert.

    Das war dann aber ein "riesiges" switch case, was ich noch dreckiger fand wie dieses nun.



  • MSS-Software schrieb:

    ich kann meine Reihenfolge der Befehle leider nicht anders umsetzen

    Klar kannst du.

    MSS-Software schrieb:

    Die Lösung, die du geschrieben hast, hatte ich auch ganz am Anfang implementiert.

    Das war dann aber ein "riesiges" switch case, was ich noch dreckiger fand wie dieses nun.

    Glaub mir, ein großes switch ist um Längen sauberer als dieses furchtbare Threadgewurschtel.

    Wenn es in deiner "Befehlssequenz" keine Verzweigungen gibt, kannst du auch einfach alle Befehle in ein Array stecken, dann brauchst du kein switch, sondern kannst einfach deinen Befehlszähler als Index benutzen.



  • stimmt

    das mit dem Array wäre echt ma ne Idee

    danke, da hab ich jetzt gar nicht dran gedacht 😉


Anmelden zum Antworten