Gostaria de saber como pode std::atomic_ref
ser implementado eficientemente (um std::mutex
por objeto) para objetos não atômicos, pois a propriedade a seguir parece bastante difícil de aplicar:
As operações atômicas aplicadas a um objeto por meio de um atomic_ref são atômicas em relação às operações atômicas aplicadas por qualquer outro atomic_ref que faz referência ao mesmo objeto.
Em particular, o seguinte código:
void set(std::vector<Big> &objs, size_t i, const Big &val) {
std::atomic_ref RefI{objs[i]};
RefI.store(val);
}
Parece bastante difícil de implementar, pois std::atomic_ref
seria necessário escolher sempre o mesmo std::mutex
(a menos que seja um grande bloqueio mestre compartilhado por todos os objetos do mesmo tipo).
Estou esquecendo de algo? Ou cada objeto é responsável por implementar std::atomic_ref
e, portanto, é atômico ou carrega um std::mutex
?
Respostas:
A implementação é muito bonito exatamente o mesmo que
std::atomic<T>
si. Este não é um problema novo.Consulte Onde está o bloqueio para um std :: atomic? Uma implementação típica de
std::atomic
/std::atomic_ref
uma tabela hash estática de bloqueios, indexada por endereço, para objetos que não são livres de bloqueio. As colisões de hash levam apenas a contenção extra, não a um problema de correção. (Os impasses ainda são impossíveis; os bloqueios são usados apenas por funções atômicas que nunca tentam levar 2 de cada vez.)No GCC, por exemplo,
std::atomic_ref
é apenas outra maneira de chamar__atomic_store
um objeto. (Veja o manual do GCC: componentes atômicos )O compilador sabe se
T
é pequeno o suficiente para ser livre de bloqueios ou não. Caso contrário, ele chama a função de biblioteca libatomic que usará o bloqueio.(fato engraçado: isso significa que só funciona se o objeto tiver alinhamento suficiente para
atomic<T>
. Mas em muitas plataformas de 32 bits, incluindo x86,uint64_t
pode ter apenas alinhamento de 4 bytes.atomic_ref
nesse objeto, ele será compilado e executado, mas não será atômico se o compilador usa um carregamento / armazenamento SSE de 8 bytes no modo de 32 bits para implementá-lo. Felizmente, não há perigo para objetos que tenhamalignof(T) == sizeof(T)
, como a maioria dos tipos primitivos nas arquiteturas de 64 bits.)fonte
atomic<T>
era permitido também em tipos não atômicos (embora esse possa tecnicamente se alocar amutex
si próprio, pois é o proprietário do objeto). Obrigado pela explicação, faz sentido.Uma implementação pode usar um hash com base no endereço do objeto para determinar qual conjunto de bloqueios adquirir ao executar a operação.
fonte
shared_ptr
objetos. github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/...