Datenübergabe zwischen zwei Threads



  • junix schrieb:

    el Clio schrieb:

    Sofern die Queue eine Klasse der Standard Template Libary ist, ist die definitiv Threadsicher!
    CriticalSections, Semaphoren etc. sind da überflüssig!

    Quelle?

    Weiß nicht mehr ganz genau, meine aber STL doku.

    junix schrieb:

    el Clio schrieb:

    Dann wirkt manchmal statt nur "Sleep()" sowas hier Wunder:

    ...
    Sleep(500);
    Application->ProcessMessages();
    ...
    

    Wieso?

    Pure Erfahrung. Grade bei dem vcl-Thread-Zeugs ist ein abarbeiten der der Nachrichten ab und an mal sinnvoll.
    Hatte auch schon mal ein ähnliches Problem, daß ich was losgeschickt habe, mit Sleep(), also blockierend gewartet habe und dann die Antwort abfragen wollte. Ergebnis: Mal gings, mal nicht.
    Durch Application->ProcessMessages(), also durch schäbiges pollen gings dann wie von Zauberhand.

    junix schrieb:

    3.4. Wenn ich jetzt nix übersehen habe, würde ich dir auch immer "nix" zurückgeben wenn ich deine Funktion wäre. 😉

    Du hast was übersehen:

    erg = messagequeue;
    

    Mist! Ich wusste, daß sowas kommt 😉

    junix schrieb:

    Noch als kleiner Gedankengang für mich: Warum gibst du eigentlich nicht einfach einen Zeiger auf deine Queue zurück statt ner Kopie?

    Weil die Queue änderungen unterworfen ist, und man ja nicht immer den Thread wieder unterbrechen will mit kurzen zugriffen? Man sollte nie Zeiger auf klasseninterne Datenstrukturen zurückliefern. Das gefährdet die Integrität

    Ja, ok! Hab nix gesagt! Je nach größe der Queue und je nach Größe der vorhandenen recourcen ist es aber manchmal sinnvoller die integrität zu gefährden, dafür aber auf die ewigen kopierereien zu verzichten. So dachte ich eigentlich 😛

    Egal. Waren alles nur so Gedanken! 😉

    Unter dem Anspeckt, daß er nun doch in die for-Schleife läuft würde mich mal interessieren, was so debug-mäßig in temp steht, also ob da vernündtiger Inhalt ankommt. Als nächstes würde mich dann interessieren, was der SubString() (von der Funktion her isses klar, aber vom Inhalt her nicht) liefert und ob der Vergleich klappt.

    Nebenbei: Sehe ich das richtig, daß "erg" am ende immer neu gesetzt wird, also beim return im besten Fall nur der Inhalt der letzten message steht?



  • el Clio schrieb:

    junix schrieb:

    el Clio schrieb:

    Sofern die Queue eine Klasse der Standard Template Libary ist, ist die definitiv Threadsicher!
    CriticalSections, Semaphoren etc. sind da überflüssig!

    Quelle?

    Weiß nicht mehr ganz genau, meine aber STL doku.

    ...konnte aber keinen Hinweis auf Threadsicherheit finden in der BCB-Dokumentation... und es wäre auch unlogisch, Threadsicherheit standardmässig einzubinden. Es gibt allerdings z.B. TThreadLIst die Threadsicher sein soll... Auf jeden Fall gilt im Zweifel immer die deffensivere Annahme zu treffen. Das schlechteste was dir da passieren kann ist, dass du doppelte Threadsicherheit implementierst. Birgt aber weniger Nachteile als keine Threadsicherheit...

    el Clio schrieb:

    junix schrieb:

    el Clio schrieb:

    Dann wirkt manchmal statt nur "Sleep()" sowas hier Wunder:

    ...
    Sleep(500);
    Application->ProcessMessages();
    ...
    

    Wieso?

    Pure Erfahrung. Grade bei dem vcl-Thread-Zeugs ist ein abarbeiten der der Nachrichten ab und an mal sinnvoll.

    ... denn sie wissen nicht was sie tun ...

    Auch beim VCL zeugs ist ein neuer Thread ein neuer Thread der ein neuer Thread ist. Da braucht es keine Abarbeitung von Nachrichten, ausser der Thread verwendet z.B. wieder ein Control auf einem Formular. Dann ists aber ohnehin müssig, irgendwas in einen Thread zu verlagern.

    el Clio schrieb:

    Hatte auch schon mal ein ähnliches Problem, daß ich was losgeschickt habe, mit Sleep(), also blockierend gewartet habe und dann die Antwort abfragen wollte. Ergebnis: Mal gings, mal nicht.
    Durch Application->ProcessMessages(), also durch schäbiges pollen gings dann wie von Zauberhand.

    Unter verwendung eines COntrols das über die Nachrichtenschleife der Applikation geht, gluab ich das sofort...

    el Clio schrieb:

    junix schrieb:

    Noch als kleiner Gedankengang für mich: Warum gibst du eigentlich nicht einfach einen Zeiger auf deine Queue zurück statt ner Kopie?

    Weil die Queue änderungen unterworfen ist, und man ja nicht immer den Thread wieder unterbrechen will mit kurzen zugriffen? Man sollte nie Zeiger auf klasseninterne Datenstrukturen zurückliefern. Das gefährdet die Integrität

    Ja, ok! Hab nix gesagt! Je nach größe der Queue und je nach Größe der vorhandenen recourcen ist es aber manchmal sinnvoller die integrität zu gefährden, dafür aber auf die ewigen kopierereien zu verzichten. So dachte ich eigentlich 😛

    ... Auch nicht falsch. Ich allerdings gehe dabei meist dazu über, das ich Datagramme einzeln aus besagtem Puffer hole und sie verarbeite. Das verhindert mir auch merkürdige Stacking-Effekte bei der Kommunikation...

    [/quote]Nebenbei: Sehe ich das richtig, daß "erg" am ende immer neu gesetzt wird, also beim return im besten Fall nur der Inhalt der letzten message steht?[/quote]Wo siehst du denn sowas?



  • junix schrieb:

    el Clio schrieb:

    Nebenbei: Sehe ich das richtig, daß "erg" am ende immer neu gesetzt wird, also beim return im besten Fall nur der Inhalt der letzten message steht?

    Wo siehst du denn sowas?

    Bei

    erg = temp.SubString(header.Length() + 3, length * 2);
    


  • Nur dann, wennauch Nachrichten in der Queue waren...



  • junix schrieb:

    Nur dann, wennauch Nachrichten in der Queue waren...

    Ja eben! Und für jede Nachricht neu. Also steht entweder "nix" drin oder eben das Ergebnis aus dem temp.SubString(), wobei in temp doch die letzte Nachricht enthält.

    Irgendwie erschließt sich mir grad der Sinn nicht wirklich!



  • Er will entweder die Nachricht oder "nix" drinne stehen haben. Wenn er jetzt die Datagramme überprüft wird das Ergbenis zunächst mit "nix" initialisiert. Geht dann aber alle datagramme durch. Wenn er den header findet, weist er diesen dem Ergebnis zu. Ansonsten kommt nix zurück.?



  • junix schrieb:

    Er will entweder die Nachricht oder "nix" drinne stehen haben. Wenn er jetzt die Datagramme überprüft wird das Ergbenis zunächst mit "nix" initialisiert. Geht dann aber alle datagramme durch. Wenn er den header findet, weist er diesen dem Ergebnis zu. Ansonsten kommt nix zurück.?

    Und wenn mehrere Header drin sind?



  • Dann scheint ihn offensichtlich nur der letzte Header zu interessieren... Nicht sauber aber machbar...?



  • So, jetzt muss ich mich auch mal wieder zu Wort melden:

    Ich habe mal ein

    Application->ProcessMessages();
    

    eingebaut, und siehe da, es wirkt tatsächlich Wunder! Auch wenn ich keine Ahnung habe warum...

    Ich werde aber trotzdem den Tipp von junix realisieren, und eine threadsichere Klasse von der Queue ableiten. Schon allein wegen des Lerneffektes.

    Vielen Dank erst mal

    Winzler



  • Winzler schrieb:

    und siehe da, es wirkt tatsächlich Wunder!

    Na sag ich ja! 🙂



  • Jetzt habe ich versucht, eine threadsichere Queue zu erstellen.

    So sieht die Definition aus:

    class MessageQueue : private deque<MostMessage>
    {
    private:
            TCriticalSection* Sperre;
    public:
            MessageQueue(void);
            void push(MostMessage);
            MostMessage at(int i);
            void clear(void);
            int size(void);
            MessageQueue get(void);
    };
    

    Und so die Implementierung:

    MessageQueue::MessageQueue(void)
    {
       Sperre = new TCriticalSection;
    }
    
    void MessageQueue::push(MostMessage message)
    {
       Sperre->Acquire();
       push_back(message);
       Sperre->Release();
    }
    
    MostMessage MessageQueue::at(int i)
    {
       Sperre->Acquire();
       MostMessage erg = deque<MostMessage>::at(i);
       Sperre->Release();
       return erg;
    }
    
    MessageQueue MessageQueue::get(void)
    {
       Sperre->Acquire();
       MessageQueue erg;
       erg = *this;
       Sperre->Release();
       return erg;
    }
    
    void MessageQueue::clear(void)
    {
       Sperre->Acquire();
       deque<MostMessage>::clear();
       Sperre->Release();
    }
    
    int MessageQueue::size(void)
    {
       int erg;
       Sperre->Acquire();
       erg = deque<MostMessage>::size();
       Sperre->Release();
       return erg;
    }
    

    Die so erstellte Queue zeigt allerdings nicht die gewünschte Wirkung. Ich habe auch schon versucht, TCriticalSection *Sperre global zu machen, also quasi so:

    TCriticalSection *s;    //globale Variable
    
    MessageQueue::MessageQueue(void)
    {
       Sperre = s;
    }
    

    Dann krieg ich folgende Warnung...

    [Linker Warnung] Public symbol '_s' defined in both module C:\PROGRAMME\CBUILDER6\PROJECTS\DLLCALL.OBJ and C:\PROGRAMME\CBUILDER6\PROJECTS\MOST.OBJ

    ...und lauter Exceptions wenn ich mein Programm aufrufe.

    Kann mir einer sagen, was ich da falsch mache? Wäre es möglich, die TCriticalSection static zu machen, damit sie für alle MessageQueues gilt?



  • Wozu brauchst du die Sperre Public machen? Sie dient ja nur dazu, deine klassen-Internen Ressourcen zu schützen.

    Es reicht also völlig, die Sperre als privates Klassenelement zu implementieren. Die Einzigen die Aquire und Release aufrufen sind ja die Funktionen die auf die klasseninterne Liste zugreifen?

    Was heisst "zeigt nicht die gewünschte Wirkung"?



  • Hast du im Übrigen irgendwelche Schleifenbildungen in deiner Hauptanwendung? Wie sieht die CPU-belastung aus?



  • "Nicht die gewünschte Wirkung" heisst, dass ich wieder Nachrichten in der Queue vermisse, die definitiv bereits empfangen wurden und die kurz darauf auch plötzlich da sind.

    In meiner Hauptanwendung gibts keine Schleifen. Meine Hauptanwendung ist lediglich ein Fenster mit Buttons, mit denen verschiedene Nachrichten verschickt werden können, deren Antwort dann ausgewertet wird.

    Die CPU-Belastung schwankt so zwischen 5 und 10 Prozent.



  • Wartet die Hauptanwendung auf irgendwas? Z.b. die Antwort?


Anmelden zum Antworten