Frage

Ich habe kleine, aber häufig verwendete Funktionsobjekte.Jeder Thread erhält eine eigene Kopie.Alles wird statisch zugewiesen.Kopien geben keine globalen oder statischen Daten weiter.Muss ich diese Objekte vor falscher Weitergabe schützen?

Danke schön.BEARBEITEN:Hier ist ein Spielzeugprogramm, das Boost.Threads verwendet.Kann es zu falschen Freigaben für das Feld kommen? Daten?

#include <boost/thread/thread.hpp>

struct Work {
    void operator()() {
        ++data;
    }

    int data;
};

int main() {
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work());
    threads.join_all();
}
War es hilfreich?

Lösung

Eine falsche gemeinsame Nutzung zwischen Threads liegt vor, wenn zwei oder mehr Threads dieselbe Cache-Zeile verwenden.

Z.B.:

struct Work {
    Work( int& d) : data( d ) {}
    void operator()() {
        ++data;
    }

    int& data;
};

int main() {
    int false_sharing[10] = { 0 };
    boost::thread_group threads;
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(false_sharing[i]));
    threads.join_all();

    int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 };
    for (int i = 0; i < 10; ++i)
        threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS]));
    threads.join_all();
}

Die Threads im ersten Block leiden unter falscher Freigabe.Die Threads im zweiten Block tun dies nicht (dank CACHELINE_SIZE).

Daten auf dem Stapel sind immer „weit“ von anderen Threads entfernt.(Z.B.unter Windows, mindestens ein paar Seiten).

Bei Ihrer Definition eines Funktionsobjekts kann es zu einer falschen Freigabe kommen, da die Instanzen von Work werden auf dem Heap erstellt und dieser Heap-Speicherplatz wird innerhalb des Threads verwendet.

Dies kann zu mehreren führen Work Instanzen müssen benachbart sein und können daher zur gemeinsamen Nutzung von Cache-Zeilen führen.

Aber ...Ihre Stichprobe macht keinen Sinn, da Daten niemals von außen berührt werden und so unnötigerweise eine falsche Weitergabe herbeigeführt wird.

Der einfachste Weg, solche Probleme zu vermeiden, besteht darin, Ihre „gemeinsamen“ Daten lokal auf den Stapel zu kopieren und dann an der Stapelkopie zu arbeiten.Wenn Ihre Arbeit fertig ist, kopieren Sie sie zurück in die Ausgabevariable.

Z.B:

struct Work {
    Work( int& d) : data( d ) {}
    void operator()()
    {
        int tmp = data;
        for( int i = 0; i < lengthy_op; ++i )
           ++tmp;
        data = tmp;
    }

    int& data;
};

Dies verhindert alle Probleme beim Teilen.

Andere Tipps

Ich habe ein faires Bit von Forschung gemacht, und es scheint, dass es keine Silberkugellösung für den falschen Teilen gibt.Hier ist das, was ich mitkomme (dank Christopher): 1) Pad Ihre Daten von beiden Seiten mit ungenutzten oder weniger häufig verwendeten Sachen. 2) Kopieren Sie Ihre Daten in Stapel und kopieren Sie ihn zurück, nachdem alles harte Arbeit erledigt ist. 3) Verwenden Sie Cache ausgerichtete Speicherzuweisung.

Ich fühle mich mit den Details nicht ganz sicher, aber hier ist meine Meinung:

(1) Ihr vereinfachtes Beispiel ist seit dem Boost fehlerhaft create_thread erwartet eine Referenz, Sie übergeben eine temporäre.

(2) wenn Sie verwenden würden vector<Work> Wenn in jedem Thread ein Element vorhanden ist oder sie andernfalls nacheinander im Speicher gespeichert sind, kommt es zu einer falschen Freigabe.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top