Falso compartilhamento e as variáveis de pilha
-
29-09-2020 - |
Pergunta
Eu tenho pequena, mas frequentemente utilizados objetos de função.Cada thread obtém a sua própria cópia.Tudo é alocado estaticamente.Cópias não partilhar quaisquer dados globais ou estáticos.Eu preciso proteger esta objetos de falso compartilhamento?
Obrigado.EDITAR:Aqui é um brinquedo programa que usa o Boost.Threads.Pode falso compartilhamento ocorrer para o campo dados?
#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();
}
Solução
Falso compartilhamento entre threads é quando 2 ou mais threads utilizam a mesma linha de cache.
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();
}
Os threads no primeiro bloco, sofrem falso compartilhamento.Os threads no segundo bloco não (graças a CACHELINE_SIZE
).
Dados na pilha é sempre "agora" longe de outros segmentos.(E. g.no windows, pelo menos, um par de páginas).
Com a sua definição de um objeto de função, falso compartilhamento pode aparecer, porque as instâncias de Work
criados na pilha e este espaço de pilha é usado dentro do segmento.
Isso pode levar a vários Work
instâncias de ser adjacentes e assim podem incorrer compartilhamento de linhas de cache.
Mas ...o seu exemplo não faz sentido, porque os dados nunca é tocado fora e tão falso compartilhamento é induzida desnecessariamente.
A maneira mais fácil, para evitar problemas como este, é para copiar 'compartilhado' dados localmente no tho a pilha e, em seguida, trabalhar na pilha de cópia.Quando terminar seu trabalho de copiar de volta para a saída var.
E. g:
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;
};
Isso impede que todos os problemas com o compartilhamento.
Outras dicas
Eu fiz um pouco de pesquisa e parece que não há bala de prata solução para false partilha.Aqui está o que eu descobri (graças a Christopher):1) Pad seus dados de ambos os lados com não utilizados ou utilizados com menos frequência coisas.2) Copie os seus dados na pilha e copiá-lo de volta depois de todo o trabalho duro é feito.3) o Uso de cache alinhado a alocação de memória.
Eu', não se sente totalmente seguro com os detalhes, mas aqui está a minha opinião:
(1) O exemplo simplificado é quebrado desde aumentar create_thread
espera de uma referência, você pode passar um temporário.
(2) se você não quiser usar vector<Work>
com um item para cada thread, ou othrwise tê-los na memória sequencialmente, falso compartilhamento irá ocorrer.