Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

235
Views
¿Por qué usar Volatile.Write en el bloqueo de doble verificación?

A continuación se muestra un código de un libro de C# para mostrar cómo se construye el patrón Singleton en subprocesos múltiples:

 internal sealed class Singleton { // s_lock is required for thread safety and having this object assumes that creating // the singleton object is more expensive than creating a System.Object object private static readonly Object s_lock = new Object(); // This field will refer to the one Singleton object private static Singleton s_value = null; // Private constructor prevents any code outside this class from creating an instance private Singleton() { // Code to initialize the one Singleton object goes here... } // Public, static method that returns the Singleton object (creating it if necessary) public static Singleton GetSingleton() { // If the Singleton was already created, just return it (this is fast) if (s_value != null) return s_value; Monitor.Enter(s_lock); // Not created, let 1 thread create it if (s_value == null) { // Still not created, create it Singleton temp = new Singleton(); // Save the reference in s_value (see discussion for details) Volatile.Write(ref s_value, temp); } Monitor.Exit(s_lock); // Return a reference to the one Singleton object return s_value; } }

Tengo la idea de por qué el código hace:

 Singleton temp = new Singleton(); Volatile.Write(ref s_value, temp);

en vez de

 s_value = new Singleton();

porque el compilador puede asignar memoria para Singleton , asignar la referencia a s_value y luego llamar al constructor. Desde la perspectiva de un solo subproceso, cambiar el orden de esta manera no tiene ningún impacto. Pero si después de publicar la referencia en s_value y antes de llamar al constructor, otro subproceso llama al método GetSingleton , entonces el subproceso verá que s_value no es nulo y comenzará a usar el objeto Singleton , pero su constructor aún no ha terminado de ejecutarse.

Pero no entiendo por qué tenemos que usar Volatile.Write , ¿no podemos hacerlo?

 Singleton temp = new Singleton(); s_value = temp;

El compilador no puede reordenar, por ejemplo, ejecutar s_value = temp primero y luego ejecutar Singleton temp = new Singleton() , porque temp tiene que existir antes de s_value = temp ?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Este código es de CLR via C# por Jeffrey Richter.

La explicación del autor en el libro (como se menciona en el comentario 'ver discusión para obtener detalles' ) es que Volatile.Write :

asegura que la referencia en temp se pueda publicar en s_value solo después de que el constructor haya terminado de ejecutarse.

Chris Brumme escribió en 2003 sobre un patrón de verificación doble de C# idéntico (los nombres de las variables cambiaron):

Funciona muy bien en X86. Pero se rompería con una implementación legal pero débil de la especificación ECMA CLI.

Suponga que se han realizado una serie de tiendas durante la construcción de [ Singleton ]. Esos almacenes se pueden reordenar arbitrariamente, incluida la posibilidad de retrasarlos hasta que el almacén de publicación asigne el nuevo objeto a [ s_value ]. En ese punto, hay una pequeña ventana antes de la tienda. La liberación implica dejar el candado. Dentro de esa ventana, otras CPU pueden navegar a través de la referencia [ s_value ] y ver una instancia parcialmente construida.

Por lo tanto, Volatile.Write solo se requiere cuando se codifica para una implementación (teórica) más débil posible del modelo de memoria estándar ECMA CLI .

NB que el estándar CLI llama a la necesidad de barreras en este caso (12.6.8):

No es un requisito explícito que una implementación conforme de la CLI garantice que todas las actualizaciones de estado realizadas dentro de un constructor sean uniformemente visibles antes de que se complete el constructor. Los generadores de CIL pueden garantizar este requisito ellos mismos insertando llamadas apropiadas a la barrera de memoria o instrucciones de escritura volátiles.

No he podido demostrar prácticamente este problema (visibilidad de una instancia parcialmente construida debido al reordenamiento) con las versiones actuales de .net en x64/ARM64 pero no lo he intentado mucho.

TLDR: escribir este tipo de código es complicado, use Lazy<T>

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!