4 votes

C# Lazy Initialization && Race-to-initialize ?

Après lecture à propos de LazyInitializer que c'est :

Il offre un autre mode d'initialisation qui fait que plusieurs threads font la course à l'initialisation.

Voici un échantillon :

Expensive _expensive;
public Expensive Expensive
     {
       get // Implement double-checked locking
         {
           LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());
           return _expensive;
         }
     }

Question n° 1

en regardant : enter image description here

pourquoi #A dit qu'il implémente le verrouillage à double vérification ? c'est juste un procédé d'obtention ?

Question n°2

Est-ce que #B (expression lambda) est thread safe ?

Question n°3

J'ai donc fait des recherches sur ce sujet "race-to-initialize" en regardant un échantillon :

volatile Expensive _expensive;
public Expensive Expensive
{
  get
  {
    if (_expensive == null)
    {
      var instance = new Expensive();
      Interlocked.CompareExchange (ref _expensive, instance, null);
    }
    return _expensive;
  }
}

et puis j'ai pensé : la course à l'initialisation n'est-elle pas thread safe ?

e/g/ si 2 fils se retrouvent dans :

enter image description here

l'objet coûteux sera créé deux fois !

Donc encore une fois, 3 questions

1)pourquoi #A dit qu'il implémente le verrouillage à double vérification ? c'est juste un procédé d'obtention ?

2)Est-ce que #B (expression lambda) est thread safe ?

3) La course à l'initialisation n'est pas un thread safe.

5voto

xanatos Points 30513

Il existe diverses surcharges de EnsureInitialized . Certains acceptent un synclock (qui peut être null et sera créé par le EnsureInitialized ). D'autres n'ont pas de synclock en tant que paramètre. Tous les EnsureInitialized garantissent que si elles sont appelées en même temps par deux (ou plus) threads différents alors que l'objet n'est pas initialisé, les deux threads recevront en retour une référence au même objet. Donc :

Expensive _expensive;

// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());

// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive,() => new Expensive());

le site _expensive L'objet qui sera vu par les deux fils sera le même.

Le seul problème est que new Expensive() pourrait être appelé deux fois (une fois par thread, donc dans une course multi-thread, il pourrait être appelé encore plus de fois).

Si vous ne le voulez pas, utilisez l'option synclock surcharge :

Expensive _expensive;
object _sync = null;
bool _useless;

// On thread 1
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());

// On thread 2
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());

Maintenant, le new Expensive() sera appelé une seule fois, pour chaque combinaison possible des deux (ou plus) threads en cours d'exécution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X