Me pregunto cómo se std::atomic_ref
puede implementar de manera eficiente (uno std::mutex
por objeto) para objetos no atómicos, ya que la siguiente propiedad parece bastante difícil de aplicar:
Las operaciones atómicas aplicadas a un objeto a través de atomic_ref son atómicas con respecto a las operaciones atómicas aplicadas a través de cualquier otra atomic_ref que haga referencia al mismo objeto.
En particular, el siguiente 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, ya std::atomic_ref
que de alguna manera necesitaría elegir cada vez lo mismo std::mutex
(a menos que sea un gran bloqueo maestro compartido por todos los objetos del mismo tipo).
¿Me estoy perdiendo de algo? ¿O cada objeto es responsable de implementar std::atomic_ref
y, por lo tanto, ser atómico o llevar un std::mutex
?
Respuestas:
La implementación es casi exactamente la misma que
std::atomic<T>
ella misma. Este no es un problema nuevo.Vea ¿Dónde está el bloqueo para un std :: atomic? Una aplicación típica de
std::atomic
/std::atomic_ref
una tabla hash estático de cerraduras, indexada por dirección, para objetos no-libre de bloqueo. Las colisiones de hash solo conducen a una contención adicional, no a un problema de corrección. (Los bloqueos siguen siendo imposibles; los bloqueos solo son utilizados por funciones atómicas que nunca intentan tomar 2 a la vez).En GCC, por ejemplo,
std::atomic_ref
es solo otra forma de invocar__atomic_store
un objeto. (Consulte el manual de GCC: incorporaciones atómicas )El compilador sabe si
T
es lo suficientemente pequeño como para ser libre de bloqueo o no. Si no, llama a la función de biblioteca libatomic que usará el bloqueo.(Dato curioso: eso significa que solo funciona si el objeto tiene suficiente alineación
atomic<T>
. Pero en muchas plataformas de 32 bits, incluida x86,uint64_t
puede que solo tenga una alineación de 4 bytes.atomic_ref
En dicho objeto se compilará y ejecutará, pero en realidad no será atómico si el compilador utiliza una carga / almacenamiento SSE de 8 bytes en modo de 32 bits para implementarlo. Afortunadamente no hay peligro para los objetos que tienenalignof(T) == sizeof(T)
, como la mayoría de los tipos primitivos en arquitecturas de 64 bits).fuente
atomic<T>
estaba permitido en tipos no atómicos (aunque técnicamente podría asignarse unomutex
, ya que posee el objeto). Gracias por la explicación, tiene sentido.Una implementación puede usar un hash basado en la dirección del objeto para determinar cuál de un conjunto de bloqueos adquirir mientras se realiza la operación.
fuente
shared_ptr
objetos. github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/…