False Freigabe zwischen Threads ist, wenn 2 oder mehr Threads die gleiche Cache-Zeile verwenden.
z. :
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 in dem ersten Block leiden falsches Teilen. Die Threads im zweiten Block nicht (Danke an CACHELINE_SIZE
).
Daten auf dem Stapel sind immer "weit" von anderen Threads entfernt. (Z. B. unter Windows, mindestens ein paar Seiten).
Mit Ihrer Definition eines Funktionsobjekts kann eine falsche Freigabe angezeigt werden, da die Instanzen Work
auf dem Heap erstellt werden und dieser Heapspeicher innerhalb des Threads verwendet wird.
Dies kann dazu führen, dass mehrere Work
Instanzen nebeneinander liegen und somit die gemeinsame Nutzung von Cache-Zeilen verursachen können.
Aber ... Ihre Stichprobe macht keinen Sinn, weil Daten nie außerhalb berührt werden und so falsches Teilen unnötig herbeigeführt wird.
Der einfachste Weg, um solche Probleme zu vermeiden, besteht darin, Ihre 'gemeinsamen' Daten lokal auf dem Stapel zu kopieren und dann an der Stapelkopie zu arbeiten. Wenn Ihre Arbeit abgeschlossen ist, kopieren Sie sie zurück in die Ausgabe var.
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, dass alle Probleme mit Teilen.
Code würde besser funktionieren. Wenn Ihre Funktionsobjekte statische Daten haben, dann teilen alle Threads diese Daten. – GManNickG
Denken Sie, dass Sie genau sagen müssen, was Sie mit "jeder Thread erhält seine eigene Kopie" und "statisch zugewiesen" meinen. Verwenden Threads die jeweils andere Kopie? – Elemental
@Elemental: Einige Compiler können lokalen TLS-Thread-Speicher verwenden. Dies bedeutet, dass Sie statische und Thread-sicher zuweisen können, obwohl dies langsam ist. – Puppy