¿Cómo se implementa std :: atomic_ref para los tipos no atómicos?


8

Me pregunto cómo se std::atomic_refpuede implementar de manera eficiente (uno std::mutexpor 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_refque 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_refy, por lo tanto, ser atómico o llevar un std::mutex?


2
Probablemente tengan un mapa de direcciones y mutexs y el aspecto del mutex que se relaciona con la dirección de los objetos. Esto permite múltiples referencias diferentes para proteger un solo objeto.
NathanOliver

Respuestas:


5

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_refuna 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_refes solo otra forma de invocar __atomic_storeun objeto. (Consulte el manual de GCC: incorporaciones atómicas )

El compilador sabe si Tes 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_tpuede que solo tenga una alineación de 4 bytes. atomic_refEn 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 tienen alignof(T) == sizeof(T), como la mayoría de los tipos primitivos en arquitecturas de 64 bits).


No me había dado cuenta de que también atomic<T>estaba permitido en tipos no atómicos (aunque técnicamente podría asignarse uno mutex, ya que posee el objeto). Gracias por la explicación, tiene sentido.
Nonyme

6

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.


Así es como libstdc ++ implementa operaciones atómicas en shared_ptrobjetos. github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/…
Brian

¿Dicha tabla hash contendría mutexes? ¿Cuándo son seguros para liberar?
Nonyme

@Nonyme En el enlace que proporcioné, puede ver que tienen una duración de almacenamiento estático.
Brian
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.