vector Threadsave read/write



  • Hallo Leute,

    ich habe ein Datarecorder.. dieser läuft in einem eigenen Thread und fügt in einem best. Intervall datensätze an einen/mehrere std::vectoren. Bei jedem Iternvall schickt der Thread eine event "Neue Datensatz" an ein fenster.
    In dem Fenster ist ein diagramm, welches ein kurve zeichnen soll anhand der Datenvectoren. vector zeit + vector dataX = eine curve.

    Über das event forder ich das fenster bzw. das diagramm auf eine kurve aus den akturellen Daten zu zeichnen. Aber während es noch zeichnt, und es länger dauern würde evtl. und der thread schon erneut einen datensatz anfügt , müsst es ja ein crash geben oder?

    Wie würded ihr das am beseten syncroniesren? Das diagram macht sich keine copy der daten, es hat einen zeiger auf die aufzeichnungdaten mit jeweils 2 iteratoren start/ende Range auf den vector.

    Wenn das diagramm den gesamten vector zeichnet und zur gleichen zeit fügt der thread ein element hinzu könnte es ja ein progarmm geben. da der vector ja evlt. durch das anfügen eines neuen elements erst umkopiert werden muss, und so das diagramm nich lesen kann.

    Wäre es sinnvoller es mit einer liste zu machen? weil ich da ja theoretisch problemmos ein element anfügen kann ohne das die davorliegenden element /iteratoren zu beeinflussen?



  • BorisDieKlinge schrieb:

    Hallo Leute,

    ich habe ein Datarecorder.. dieser läuft in einem eigenen Thread und fügt in einem best. Intervall datensätze an einen/mehrere std::vectoren. Bei jedem Iternvall schickt der Thread eine event "Neue Datensatz" an ein fenster.
    In dem Fenster ist ein diagramm, welches ein kurve zeichnen soll anhand der Datenvectoren. vector zeit + vector dataX = eine curve.

    Heisst "Event" in diesem Kontext eine Windows-Event? Welche Plattform benutzt Du? Welche Thread API benutzt Du?

    BorisDieKlinge schrieb:

    Über das event forder ich das fenster bzw. das diagramm auf eine kurve aus den akturellen Daten zu zeichnen. Aber während es noch zeichnt, und es länger dauern würde evtl. und der thread schon erneut einen datensatz anfügt , müsst es ja ein crash geben oder?

    Wenn was länger dauern würde? Wenn das Zeichnen länger dauert als das Lesen?

    BorisDieKlinge schrieb:

    Wie würded ihr das am beseten syncroniesren? Das diagram macht sich keine copy der daten, es hat einen zeiger auf die aufzeichnungdaten mit jeweils 2 iteratoren start/ende Range auf den vector.

    😕

    BorisDieKlinge schrieb:

    Wenn das diagramm den gesamten vector zeichnet und zur gleichen zeit fügt der thread ein element hinzu könnte es ja ein progarmm geben. da der vector ja evlt. durch das anfügen eines neuen elements erst umkopiert werden muss, und so das diagramm nich lesen kann.

    Wenn was passiert, kann es was geben? Ein Programm? Ein Problem? Muss der Vektor das Diagramm lesen?

    BorisDieKlinge schrieb:

    Wäre es sinnvoller es mit einer liste zu machen? weil ich da ja theoretisch problemmos ein element anfügen kann ohne das die davorliegenden element /iteratoren zu beeinflussen?

    Sinnvoll wäre hier eine Queue. Die STL Queue ist aber nicht zwangsläufig Threadsafe ( die Wahrscheinlichkeit, dass sie es nicht ist, ist sogar ziemlich groß). Du solltest Dir also vielleicht eine eigene Klasse zur Entkopplung von Producer und Consumer bauen bzw. einen passenden STL-Container Threadsafe kapseln.



  • Hi sorry wegen meinem deutsch:) Mit Event meine ich Window Message plattform Windows WinAPI 🙂

    Ja es könnte je nach anzahl der Daten länger dauern das Diagramm zu zeichnen als einen datensatz hinzuzufügen:)

    habe mir überlegt den Aufzeichnungs kontainer ungefähr so aufzubauen:

    class DataRecording{
      Mutex mx;
    
    std::list<dat> m_DATA;
    
     void addData(...){
        Lock(mx);
    
        m_DATA.push_back(....);
     }
    
     std::list<dat>::iterator GetLastRecord(){
        Lock(mx);
        return m_DATA.end();
     }
    };
    

    Thread Ruft dann die addDATA funktion auf, und meine Diagrmm ruft
    GetLastRecord auf... das Diagramm darf ja jetzt die Daten bis zumletzen Record lesen ohne , und der thread derweil einen neuen anfügen...

    Thread:

    ThreadLoop(){
    
    obj.addData();
    PostMessage(WM_NEWDATA);
    Sleep(1000);
    }
    

    Diagrammfenster:

    OnNewData(..){
    
       GetLastRecord();
    //Diagramm zeichnen
    }
    


  • Würde ich mich nicht drauf verlassen... Ist es ausgeschlossen, dass beim Hinzufügen neuer Datensäte, die bestehenden Datensätze in einen neuen Speicherbereich kopiert werden müssen (ich weiss nicht wie vector das handhabt)?

    Dem Thread würde ich einen internen Puffer spendieren und TryLock() statt Lock() verwenden. Wenn nicht gesperrt werden kann, schreibst Du die Daten, bis zum nächsten Zyklus, einfach in den internen Puffer.



  • naja während das Fenster zeichnet, und der Thread fügt einen neuen datensatz hinzu
    muss ja nicht direkt wieder neu gezeichnet werden.. dann brauch ich da keinen puffer...

    auserdem kann das Fenster ja asyncron zeichnen, weil es ja aus dem datenbereich liest, in dem der Thread nichts macht. .er fügt ja nur an, und verändert nichts...



  • BorisDieKlinge schrieb:

    naja während das Fenster zeichnet, und der Thread fügt einen neuen datensatz hinzu
    muss ja nicht direkt wieder neu gezeichnet werden.. dann brauch ich da keinen puffer...

    auserdem kann das Fenster ja asyncron zeichnen, weil es ja aus dem datenbereich liest, in dem der Thread nichts macht. .er fügt ja nur an, und verändert nichts...

    Deshalb sagte ich ja: Queue.
    Der Producer (Dein Rekorder) schiebt hinten was in die Queue rein. Der Consumer (Dein Fenster) entnimmt den vordersten Wert oder wartet, wenn nichts da ist.



  • ne das geht nich, der recorder zeichnet ja kontinuierlich auf von start bis ende.. das heist das Datenvolumen steigt kontinuerlich dem aufzeichnusintervall..

    das diagrm zeichnet alles daten von start der aufzeichnung bist zum gegenwärtigen zeitpunkt, oder man definiert die Zeit von der gegenwart bist - X! und diese rbereich kann ich ja mit iteratoren definierren. deswegen liste...



  • BorisDieKlinge schrieb:

    ne das geht nich, der recorder zeichnet ja kontinuierlich auf von start bis ende.. das heist das Datenvolumen steigt kontinuerlich dem aufzeichnusintervall..

    das diagrm zeichnet alles daten von start der aufzeichnung bist zum gegenwärtigen zeitpunkt, oder man definiert die Zeit von der gegenwart bist - X! und diese rbereich kann ich ja mit iteratoren definierren. deswegen liste...

    Und? Jeder aufgezeichnete Wert wandert in die Queue. Wenn das Zeichnen etwas länger dauert als das Einlesen, füllt sich die Queue halt langsam. Immer wenn der Zeichner mit dem Zeichnen eines Datums fertig ist, nimmt er sich das Nächste aus der Queue raus. Wo soll das Problem sein?
    Wenn die aufgezeichneten Daten endlos lang sind, hättest Du ein Problem, wenn das Erzeugen schneller geht als das Verbrauchen. Aber das hättest Du dann so oder so.
    PS: Wenn Du eh Win-API-Messages benutzt, könntest Du die Daten auch an die Message hängen. Die Messages werden nämlich vom OS für Dich gequeued.



  • du meinst ne queue als puffer für das diagramm zwischen recording daten?

    Das Diagram soll abe keine eigenen container bzw. queue haben, sondern den primären list container des thread verwenden...

    vll. reden wir aneinander vorbei^^



  • BorisDieKlinge schrieb:

    du meinst ne queue als puffer für das diagramm zwischen recording daten?

    Das Diagram soll abe keine eigenen container bzw. queue haben, sondern den primären list container des thread verwenden...

    vll. reden wir aneinander vorbei^^

    Du hast doch nur einen Puffer. Der Producer schreibt rein, der Consumer liest raus. Wozu zwei?

    Du beißt Dich viel zu sehr an die STL Strukturen fest. Für Dich bedeutet Queue=std::queue, oder? Ich meinte Queue als generalles Konzept zur Entkopplung bei Producer/Consumer Konstrukten:
    Queue.
    Mal davon abgesehen ist std::queue nur ein Adapter um einen Container der FIFO-Verhalten erzwingt. Als unterliegende Datenstruktur kannst Du auch eine std::list nehmen, wenn Dich das glüklich macht. Dafault ist std::deque.



  • ich versteh nich wieso ein puffer....

    Der Thread fügt die daten hinzu.... nicht die diagramm....

    du meinst der thread liefert nen datensatz und mit der message OnNEWDATA soll das diagrmm den datensatz an die list anfügen?



  • Lies nochmal meinen letzten Post. Ich habe da nochmal editiert. Siehe auch den Wikipedialink. Da gibts ne Grafik die schön zeigt, worum es geht.



  • ich weis was ne queue ist , aber ich weis nich was die mir nutzen soll^^ Der Thread fügt records an die liste hinzu egal ob die Grafik die list derweil liest und zeichnet. solange sie nur bist zu dem element der list liest, wo der thread nichts machts...

    WEil ich die die elemente der list ja nicht mehr rauschmeise, was drin ist ist drin;) das diagramm soll nur die letzen X elemente anzeigen;)



  • BorisDieKlinge schrieb:

    ich weis was ne queue ist , aber ich weis nich was die mir nutzen soll^^

    Was ist darann denn so schwer? Der Thread packt Daten in die Queue rein (er ist der Producer), Dein Zeichnen-Ding entnimmt Datan aus der Queue (das ist der Consumer).
    Du magst vielleicht wissen, was eine Queue ist, aber Du hast anscheinend den Sinn davon noch nicht verstanden.

    |-----------------------|                  |-----------------------|
    |Thread                 |                  | Zeichnen Thread       |
    |                       |                  |                       |
    |                       |                  |                       |
    |   Daten               |                  |        Daten          |
    |     |                 |    Queue         |         /\            |
    |     |      |---|---|---|---|---|---|---|---|---|    |            |
    |     |--->  |   |   |   |   |   |   |   |   |   | ---|            |
    |            |---|---|---|---|---|---|---|---|---|                 |
    |                       |                  |                       |
    |                       |                  |                       |
    |                       |                  |                       |
    |                       |                  |                       |
    |                       |                  |                       |
    |-----------------------|                  |-----------------------|
    


  • Was ist darann denn so schwer? Der Thread packt Daten in die Queue rein (er ist der Producer), Dein Zeichnen-Ding entnimmt Datan aus der Queue (das ist der Consumer).
    Du magst vielleicht wissen, was eine Queue ist, aber Du hast anscheinend den Sinn davon noch nicht verstanden.

    genau das will ich nicht.....

    beim anlegen eine aufzeichnung wird eine recording objekt angelegt, jede sekunde für der thread daten hinzu.

    Das Diagramm macht nichts anderes als Diese Daten noch anzuzeigen, muss aber nicht... das diagramm hat also nur eine referen aufdie list.. und zeig die daten an.. die eigentlich aufzeichnung macht ja der thread

    aber danke für den denkansatz 🙂 🙂



  • BorisDieKlinge schrieb:

    ich weis was ne queue ist , aber ich weis nich was die mir nutzen soll^^ Der Thread fügt records an die liste hinzu egal ob die Grafik die list derweil liest und zeichnet. solange sie nur bist zu dem element der list liest, wo der thread nichts machts...

    WEil ich die die elemente der list ja nicht mehr rauschmeise, was drin ist ist drin;) das diagramm soll nur die letzen X elemente anzeigen;)

    Ich verstehe den Post nichtmal im Ansatz. Probier mal die Shift-Taste aus...



  • ----------------------
    thread
    
    List:
    <1> <2> <3> <4> <5> 
    
    ----------------------
    
    ----------------------
    UI grahic
    
    referen auf list un
    iterator auf <1> und <5>
    
    ---------------------
    

    der thread fügt jetzt ein neues element an <6>
    die UI zeichnet die kurven von <1> bis <5>
    die kurve muss also nicht UNBEDING Syncron im takt wie der thread die punkte zeichen...

    die List im thread wird gleichzeitig in ne datei gespeichert..



  • Da wäre ne Queue perfekt...
    Die Nichtsynchronität ist doch gerade der Sinn der Queue. Die entkoppelt den Producer vom Consumer.
    Der Rekorder packt einfach immer was rein. Egel wie er gerade lustig ist. Der Zeichner nimmt einfach was raus, so schnell er kann.
    Wenn der Zeichner schneller ist als der Rekorder, läuft die Queue leer. Der Zeichner muss warten, bis wieder was zum Zeichnen da ist.
    Wenn der Rekorder schneller ist als der Zeichner füllt sich die Queue langsam bis der Rekorder fertig ist.
    Da ist nichts synchron. Der Zeichner versucht zu zeichnen, wenn er es möchte, und der Rokorder packt was rein, wenn er möchte.
    Und es gibt auch nur eine Queue. Der eine packt was rein, der andere nimmt was raus.



  • wo werden die daten dann gespeichert?? wenn der thread sie in die queue gibt, und das diagamm sie abholt? ich will die aufgezeichneten daten später wieder anschaun kkönnen, in dem ich die datensätze lade...



  • Der Rekorder kann doch direkt jeden aufgezeichneten Datensatz gleichzeitig zum in die Queue packen auch wegspeichern. Wieso muss es dafür erst in einer Liste stehen?



  • Hm, dazu gleich noch eine Frage...

    Selbst wenn man die Queue mittels zB einer CriticalSection Thread-Safe macht, könnte das zu Problemem führen. So weit ich weiß, darf immer nur der Prozess, der Objekte erzeugt hat, diese auch wieder löschen. Wenn aber nun der Producer die Daten in die Queue schreibt und der Consumter sie ausliest, werden die Objekte vom Producer erzeugt, aber vom Consumer gelöscht. Und genau das könnte ein Problem mit der Speicherverwaltung geben, oder nicht?


Anmelden zum Antworten