openmp thread safe container



  • Hallo!

    Ich möchte meinen Datensatz in einer openmp for schleife verarbeiten. Ausnahmeresultate sollen in einem container gespeichert werden. So in etwa:

    std::vector< std::string > ausnahmen;
    
    #pragma omp parallel for shared( ausnamen )
    for( ... )
    {
        // ... berechne
        if( falsche_berechnung )
        {
            ausnahmen.push_back( ... )
        }
    }
    

    Darf ich so etwas machen? Eigentlich will ich die for schleife abbrechen sobald eine falsche berechnung passiert aber das geht soweit ich es verstanden habe nicht in einer parallel for.

    Gibt es multiple thread write safe container oder muss ich locks einführen? Wie löse ich so etwas?


  • Mod

    vector::push_back ist im Allgemeinen absolut nicht tread-safe. Ebenso hat kein anderer STL-Container garantiert thread-safe Einfügefunktionen. Geht schließlich auch schlecht ohne Locks oder massiven Aufwand, da offensichtlich ein Einfügen von Elementen die Containerstruktur verändern wird. Es gibt in Boost lock-free Queues und Stacks. Das wäre vielleicht etwas für dich, da du keinen Indexzugriff zu benötigen scheinst. Es gibt auch zahlreiche thread-safe Implementierungen von Vector, z.B. in Intels TBB, die dann intern mit Locks arbeiten, was eventuell performanter ist, als wenn du selber das Locking außendrum machst (weil die internen Locks dann genau nur an den kritischen Stellen sind).

    Allgemein:
    Warum muss der Container denn geshared sein? Warum nicht erst am Ende der Schleife akkumulieren¹? Wenn du sowieso bei jeder Ausnahme abbrechen möchtest, warum dann überhaupt ein Container, anstatt einem (atomic) bool-Indikator? Das würde dann auch teilweise dein Problem mindern, dass du nicht aus der Schleife ausbrechen kannst: Zwar kannst du immer noch nicht abbrechen, aber du kannst vor jedem Durchlauf checken, ob der Abbruchindikator gesetzt ist und dir in dem Fall eine weitere Rechnung sparen.

    edit:
    ¹: Ok, custom reductions in OpenMP sind nicht gerade so toll, kann verstehen, wenn man das nicht machen möchte.



  • SeppJ schrieb:

    Warum muss der Container denn geshared sein?

    Ich habe nicht viel Ahnung von OpenMP und dachte, dass er shared sein muss damit alle threads da hineinschreiben können.

    SeppJ schrieb:

    Warum nicht erst am Ende der Schleife akkumulieren¹?

    Wusste nicht dass es so etwas gibt. Die richtige Reihenfolge kann ich mir ja später anhand von ids aufbauen. Reduction war ein gutes Stichwort, danke!

    SeppJ schrieb:

    Wenn du sowieso bei jeder Ausnahme abbrechen möchtest, warum dann überhaupt ein Container, anstatt einem (atomic) bool-Indikator? Das würde dann auch teilweise dein Problem mindern, dass du nicht aus der Schleife ausbrechen kannst: Zwar kannst du immer noch nicht abbrechen, aber du kannst vor jedem Durchlauf checken, ob der Abbruchindikator gesetzt ist und dir in dem Fall eine weitere Rechnung sparen.

    Ich denke dass ist mein erster Ansatz bis ich etwas brauchbares mit Reductions habe. Im Prinzip muss ich abbrechen weil schon ein einzelner falscher Wert das Gesamtergebnis unbrauchbar machen kann. Andererseits möchte ich den Nutzer nicht 10 mal das Programm starten lassen damit er alle 10 Fehler einzeln korrigiert sondern am besten eine Übersicht mit mangelhaften Zeilen und den dazu passenden Fehlerbeschreibungen.


  • Mod

    Ist zwar vielleicht nicht das eleganteste was die Ausgabe von Fehlermeldungen angeht, aber printf ist bei der libgcc threadsafe.

    Ansonsten habe ich oben noch hinzu editiert, dass OpenMP nicht so toll ist, was Reductions angeht, daher ist das (automatische) Akkumulieren von Vectoren vielleicht doch nicht so super. Was du natürlich recht einfach machen könntest, ist, manuell einen Vector von Vectoren anzulegen und jeder Thread schreibt dann in seinen eigenen. Das wäre threadsicher, relativ einfach machbar, und du hast am Ende alle Meldungen.


Anmelden zum Antworten