2011-05-28 12 views
13

LazyThreadSafetyMode belgesi, ExecutionAndPublication değerini kullanarak başlatma yöntemini (veya başlatma yöntemi yoksa varsayılan yapıcı) kilitleri dahili olarak kullanırsa deadlock'lere neden olabileceğini belirtir. Bu değeri kullanırken bir kilitlenmeye neden olabilecek örneklerin daha iyi anlaşılmasına çalışıyorum. Bu değeri kullanmamda, ChannelFactory başlatıyorum. Herhangi bir dahili kilit kullanarak (Reflektörlü sınıfı gözden geçirerek) ChannelFactory'un yapıcısını göremiyorum, bu yüzden bu senaryonun olası bir kilitlenme durumuna uymadığını düşünüyorum, ancak olası bir durumun ortaya çıkması durumunda hangi durumların çıkmaza neden olabileceğini merak ediyorum. ChannelFactory'yi başlatan kilitlenme.Lazy <T> ExecutionAndPublication - Deadlock'a Neden Olabilecek Örnekler

Özetlemek gerekirse, sorularım şunlardır:

  1. o ExecutionAndPublication kullanarak ChannelFactory başlatılırken bir kilitlenmeye neden mümkün mü?

  2. ExecutionAndPublication'ı kullanarak diğer nesneleri başlatacak bir kilitlemeye neden olmanın bazı olası yolları nelerdir?

aşağıdaki kodu olduğunu varsayalım:

class x 
{ 
    static Lazy<ChannelFactory<ISomeChannel>> lcf = 
     new Lazy<ChannelFactory<ISomeChannel>>(
     () => new ChannelFactory<ISomeChannel>("someEndPointConfig"), 
     LazyThreadSafetyMode.ExecutionAndPublication 
     ); 

    public static ISomeChannel Create() 
    { 
     return lcf.Value.CreateChannel(); 
    } 
} 

cevap

9
  1. Bu belgelendiği gibi - bu kilitleri kullanmıyorsa, bu kullanım herhangi kilitlenmeleri neden olamaz.
  2. Veritabanından okuyarak başlattığınız tembel bir değeriniz olduğunu düşünün, ancak her an için yalnızca bir iş parçacığının DB'ye eriştiğinden emin olmak istersiniz. DB'ye erişen başka bir kodunuz varsa, bir kilitlenme olabilir. Aşağıdaki kodu düşünün: o kilidi kullanmak zorunda böylece
void Main() 
{ 
    Task otherThread = Task.Factory.StartNew(() => UpdateDb(43)); 
    Thread.Sleep(100); 
    Console.WriteLine(lazyInt.Value); 
} 

static object l = new object(); 
Lazy<int> lazyInt = new Lazy<int>(Init, LazyThreadSafetyMode.ExecutionAndPublication); 

static int Init() 
{ 
    lock(l) 
    { 
     return ReadFromDb(); 
    } 
} 

void UpdateDb(int newValue) 
{ 
    lock(l) 
    { 
     // to make sure deadlock occurs every time 
     Thread.Sleep(1000); 

     if (newValue != lazyInt.Value) 
     { 
      // some code that requires the lock 
     } 
    } 
} 

Init(), DB'den okur. UpdateDb() DB'ye yazıyor, bu yüzden de kilitlemeye ihtiyaç duyuyor ve bu durumda Lazy dahili olarak da bir kilit kullandığı için, bu durum kilitlenmeye neden oluyor.

Bu durumda, kilit ifadesinin dışındaki UpdateDb() numaralı telefona lazyInt.Value erişimini taşıyarak kilitlenmeyi düzeltmek kolay olurdu, ancak diğer durumlarda önemsiz (veya belirgin) olmayabilir.

+1

Harika cevap @svick - zıt düzende elde edilen iç içe geçmiş kilitlerin klasik örneği, bu düşündüğüm çizgilerin çizgisi boyunca - senaryoya açıklık getirmek için harika bir örnek, teşekkürler! – dugas