Falso intercambio entre hilos es cuando 2 o más hilos utilizan la misma línea de caché.
E.g. :
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();
}
Los hilos en el primer bloque sufren de uso compartido falso. Los hilos en el segundo bloque no (gracias a CACHELINE_SIZE
).
Los datos en la pila siempre están "lejos" de otros hilos. (Por ejemplo, en Windows, al menos un par de páginas).
Con su definición de objeto de función, puede aparecer el uso compartido falso, porque las instancias de Work
se crean en el montón y este espacio de montón se utiliza dentro del subproceso.
Esto puede provocar que varias instancias Work
sean adyacentes y, por lo tanto, puede incurrir en el intercambio de líneas de caché.
Pero ... su muestra no tiene sentido, porque los datos nunca se tocan fuera, por lo que el intercambio falso se produce de forma innecesaria.
La manera más fácil, para evitar problemas como este, es copiar los datos 'compartidos' localmente en la pila y luego trabajar en la copia de la pila. Cuando su trabajo finalice, cópielo de nuevo a la var. De salida.
por ejemplo:
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;
};
Esto evita todos los problemas con el uso compartido.
El código funcionaría mejor. Si los objetos de su función tienen datos 'estáticos', entonces todos los hilos compartirán esos datos. – GManNickG
Creo que necesita decir exactamente lo que quiere decir con "cada hilo obtiene su propia copia" y "asignada estáticamente". ¿Los hilos usan la copia de los demás? – Elemental
@Elemental: algunos compiladores pueden usar el almacenamiento local TLS-thread. Esto significa que puede asignar estáticamente AND thread-safe, aunque es lento. – Puppy