std::list und MultiThread...



  • Guest_111 schrieb:

    Oder hab ich da was übersehen?

    Ja. push_back erzeugt nicht nur einen neuen Listenknoten, sondern verändert auch den letzten Listenknoten (falls vorhanden), nämlich dessen next-Pointer.
    pop_front löscht nicht nur den ersten Listenknoten sondern modifiziert auch noch den zweiten (der zum ersten wird, falls vorhanden), nämlich dessen prev-Pointer.

    Wenn bei einer Liste mit zwei Elementen gleichzeitig push_back und pop_front ausführst, wird also gleichzeitig das zweite Element bearbeitet, wenngleich es unterschiedliche Member des Knotens sind. Klingt irgendwie trotzdem potentiell ungesund.
    Wenn du bei einer Liste mit nur einem Element gleichzeitig push_back und pop_front machst gibts Chaos: der neu hinten angefügte Listenknoten könnte einen prev-Pointer erhalten, der auf den im selben Moment gelöschten Knoten zeigt, also ins Nirvana.

    Dazu kommt das Problem mit der Größe: std::list wird vermutlich ihre Größe in einer Variablen speichern. Beide Methoden werden die gleichzeitig inkrementieren und dekrementieren, ein klassischer Lehrbuchfall für eine Race Condition.



  • Danke euch für die schnellen Antworten,

    wie ich sehe hab ich etwas viel übersehen 😉 Aber dafür gibts ja solche Foren...

    Komm wohl über das Kopieren der List nicht drumherum.

    Vielen Dank und viel spass noch beim coden



  • Passend dazu folgener Artikel: Writing Lock-Free Code: A Corrected Queue



  • Wenn ich noch kontrolliere das die max Grösse der Liste nicht überschritten wird, müsste dies doch eigentlich schon synchron sein...

    Nein.

    Oder hab ich da was übersehen?

    Übersehen ist nicht das richtige Wort. Die fehlen nur die Grundlagen um überhaupt beurteilen zu können ob etwas threadsafe ist.

    Davon abgesehen gilt: ob eine Library-Funktion threadsafe ist, und was mit threadsafe gemeint ist, findest du in der Doku. Wenn diesbezüglich nix drinnen steht, musst du davon ausgehen, dass sie nicht threadsafe ist. Da im C++ Standard diesbezüglich nix steht... -> nichts ist threadsafe.



  • Guest_111 schrieb:

    Komm wohl über das Kopieren der List nicht drumherum.

    Warum solltest du die Liste kopieren müssen?



  • @hustbaer
    Hab ja im ersten Satz von diesem Artikel geschrieben das sie nicht ThreadSafe ist...

    @l'abra d'or
    Meine Applikation:
    Thread A empfängt Packete auf einem Socket
    Thread B holt diese immer ab

    Wenn nun ununterbrochen auf dem Socket geschrieben wird, wird der Mutex ja praktisch nie freigegeben... So muss ich das Zeugs kopieren um eine Art "neutrale Liste" zu erhalten...
    --> Thread A empfängt speichert in Liste A, Kopiert Liste A in B
    --> Thread B holt Daten von Liste B

    Gruss



  • Guest_111 schrieb:

    Wenn nun ununterbrochen auf dem Socket geschrieben wird, wird der Mutex ja praktisch nie freigegeben... So muss ich das Zeugs kopieren um eine Art "neutrale Liste" zu erhalten...
    --> Thread A empfängt speichert in Liste A, Kopiert Liste A in B
    --> Thread B holt Daten von Liste B

    Komiker...
    Das umkopieren musst du ja auch mit ner Mutex absichern, sonst stehst du vor dem selben Problem, dass während dem Umkopieren die Liesten manipuliert weden.



  • pumuckl schrieb:

    Guest_111 schrieb:

    Oder hab ich da was übersehen?

    Ja. push_back erzeugt nicht nur einen neuen Listenknoten, sondern verändert auch den letzten Listenknoten (falls vorhanden), nämlich dessen next-Pointer.
    pop_front löscht nicht nur den ersten Listenknoten sondern modifiziert auch noch den zweiten (der zum ersten wird, falls vorhanden), nämlich dessen prev-Pointer.

    Wenn bei einer Liste mit zwei Elementen gleichzeitig push_back und pop_front ausführst, wird also gleichzeitig das zweite Element bearbeitet, wenngleich es unterschiedliche Member des Knotens sind. Klingt irgendwie trotzdem potentiell ungesund.
    Wenn du bei einer Liste mit nur einem Element gleichzeitig push_back und pop_front machst gibts Chaos: der neu hinten angefügte Listenknoten könnte einen prev-Pointer erhalten, der auf den im selben Moment gelöschten Knoten zeigt, also ins Nirvana.

    Dazu kommt das Problem mit der Größe: std::list wird vermutlich ihre Größe in einer Variablen speichern. Beide Methoden werden die gleichzeitig inkrementieren und dekrementieren, ein klassischer Lehrbuchfall für eine Race Condition.

    Der Punkt ist einfach: es macht kaum Sinn, sich über sowas Gedanken zu machen, wenn es nicht garantiert wird. Und das wird es nicht. Das ist auch das was ich mit meinem Beitrag zum Ausdruck bringen wollte.

    Nur weil man sich z.B. vorstellen würde man könnte oder sollte eine std::list so-oder-so implementieren, und dass bei einer solchen Implementierung dieses oder jenes "automatisch" thread-safe wäre, kann man sich noch lange nicht darauf verlassen, dass es das auch wirklich ist.



  • hustbaer schrieb:

    Nur weil man sich z.B. vorstellen würde man könnte oder sollte eine std::list so-oder-so implementieren, und dass bei einer solchen Implementierung dieses oder jenes "automatisch" thread-safe wäre, kann man sich noch lange nicht darauf verlassen, dass es das auch wirklich ist.

    Meine Argumentation war auch exakt gegenteilig. Weil diverse Implementierungen erlaubt und möglich sind, die nicht threadsafe sind, ist std::list auch nicht garantiert threadsafe.



  • pumuckl schrieb:

    hustbaer schrieb:

    Nur weil man sich z.B. vorstellen würde man könnte oder sollte eine std::list so-oder-so implementieren, und dass bei einer solchen Implementierung dieses oder jenes "automatisch" thread-safe wäre, kann man sich noch lange nicht darauf verlassen, dass es das auch wirklich ist.

    Meine Argumentation war auch exakt gegenteilig. Weil diverse Implementierungen erlaubt und möglich sind, die nicht threadsafe sind, ist std::list auch nicht garantiert threadsafe.

    Ist mir schon klar.
    Ich finde nur die Art wie du es dargelegt hast ... potentiell irreführend.

    Im Leser könnte die Idee aufkommen, man müsse sich nur durchdenken wie etwas implementiert sein könnte, und könne daraus schliessen ob es nicht vielleicht auch ohne externe Synchronisierung Thread-Safe sein könnte.

    Und IMO ist das der falsche Ansatz. Es ist für jede Funktion jeder Klasse möglich, eine standardkonforme Implementierung zu schreiben, die nicht Thread-Safe ist. Ganz egal wie einfach die Funktion vielleicht ist.

    Daher ist IMO der einzig sinnvolle Ansatz: "gucken was draufsteht", und sich danach richten.


Anmelden zum Antworten