2011-11-26 8 views
8

yılında kilitleme atılı 'üzerine Eşzamanlı programlama pencereler'Çift gerekli olduğunu 'uçucu' operasyonu ne tür Joe Duffy kitabından DCL kodunu aldı .NET

class LazyInit<T> where T : class 
{ 
private volatile T m_value; 
private object m_sync = new object(); 
private Func<T> m_factory; 
public LazyInit(Func<T> factory) { m_factory = factory; } 
public T value 
{ 
    get 
    { 
    if (m_value == null) 
    { 
     lock (m_sync) 
     { 
     if (m_value == null) 
     { 
      m_value = m_factory(); 
     } 
     } 
    } 
    return m_value; 
    } 
} 
} 

bu söylenir önleyebilir işaretleme m_value uçucu yeniden başlatmayı, diğer konuların "başlatılmamış alanlarla boş olmayan nesne" oluşturmasına yol açacağını yazar. Sorun sadece olası yazımların yeniden sıralanmasından kaynaklanıyorsa, aşağıdaki gibi dosyalanmış uçucuyu işaretlemek yerine 'Uçucu Yazma'yı kullanabilir miyim?

class LazyInit<T> where T : class 
{ 
private object m_value; 
private object m_sync = new object(); 
private Func<T> m_factory; 
public LazyInit(Func<T> factory) { m_factory = factory; } 
public T value 
{ 
    get 
    { 
    if (m_value == null) 
    { 
     lock (m_sync) 
     { 
     if (m_value == null) 
     { 
      Thread.VolatileWrite(ref m_value, m_factory()); 
     } 
     } 
    } 
    return (T)m_value; 
    } 
} 
} 

İlgili bir soru kitabı

class LazylnitRelaxedRef<T> where T : class 
{ 
private volatile T m_value; 
private Func<T> m_factory; 
public LazylnitRelaxedRef(Func<T> factory) { m_factory = factory; } 
public T Value 
{ 
    get 
    { 
    if (m_value == null) 
     Interlocked.CompareExchange(ref m_value, m_factory(), null); 
    return m_value; 
    } 
} 
} 

den İçten kilitli sürümü yana olduğunu (Bu kod Tek bildiğim yerine uçucu yazma kullanabilirsiniz eğer emin olmak, gösteri için biraz garip görünüyor) ECMA-CLI, 'Kilitli işlemin örtülü edinme/serbest bırakma işlemlerini gerçekleştirmesini' şart koşar, bu durumda hala uçucuya ihtiyacımız var mı?

+2

ECMA bellek modeli ve .net 2 bellek modeli arasında önemli bir fark vardır. – CodesInChaos

+0

Neden çift kilitleme kilitlemesi yapmalısınız? Başvurunuzda bir kilit alma ile bir performans sorunu gözlemlediniz mi? –

+1

@CodeInChaos, lütfen "önemli farkın" ne olduğunu açıklayın. – Amy

cevap

1

İlk olarak, uçucu ile uğraşmak çok zor, bu yüzden çok fazla gevşeme! Ancak, here soruna gerçekten yakın bir yanıttır ve here, herkesin volatile anahtar sözcüğünü kullanmadan önce okuması gerektiğini ve kesinlikle VolatileRead, VolatileWrite ve MemoryBarrier'u kullanmaya başlamadan önce yazması gereken bir makaledir.

İlk bağlantıdaki yanıt: Hayır, uçucu kullanmanıza gerek yok, sadece yeni değeri atamadan ÖNCE System.Threading.Thread.MemoryBarrier() SAĞ kullanmanız gerekir. Bunun nedeni, volatil anahtar sözcüğünü kullanırken ima edilen release_fence, ana belleğe yazmayı bitirdiğini ve tamamlanıncaya kadar hiçbir okuma/yazma işleminin gerçekleştirilemeyeceğini gösterir.

Peki, Thread.VolatileWrite() ne yapar ve 'volatile' anahtar sözcüğünden aldığımız aynı işlevleri gerçekleştirir mi? İşte tam kodu bu işlevinden var:

public static void VolatileWrite (ref int address, int value) 
{ 
    MemoryBarrier(); address = value; 
} 

Evet, bu yeterlidir değerinizi, atar hemen önce MemoryBarrier çağrısı!

+0

, Kod tarafından yanılttığınız için üzgünüm, DCL için, eğer okuma uçucu değilse ya da okuma çitini almazsa, bazı zayıf bellek modellerinde sorun var mıydı? BTW, .net API Thread.VolatileRead ve Thread.VolatileWrite uygulanması için tam çit kullanır, yani onlar bir uçucu okuma ve bir uçucu yazma daha güçlü oldukları anlamına gelir. Benim soru için, API okuma değil, uçucu okuma durumu ele alalım. (Yine, kodu tarafından yanıltıcı için üzgünüm) – Fei

+1

Orijinal uçucu davranış, yazma öncesi ve okumadan sonra bir bariyer koymaktır. Yazma işlemlerinden önce ve sonra ve bir okuma işleminden önce bir bellek engeli öneririm. Eğer yazıp sonra hemen okursak, bu 2 operasyonun aralarında herhangi bir engel bulunmadığından dolayı değiş tokuş edilir. –

+0

@Ivaylo Slavov, 'takas' için, bu durumda DCL'yi kırmak için ne olacağı konusunda bana daha fazla bilgi verebilir misiniz? BTW, bu 'takas' veri bağımlılığını kıracak mı? – Fei

İlgili konular