2016-11-29 27 views
5

Bu yüzden bir ödev için C# -Lock kullanma veya kendi kendine uygulanan bir TaS-Lock kullanma seçeneğine sahip olmamız gerekir. TaS-Locks hakkında okuduğum şey, bir değeri okumak ve yazmak için 1 atomik adım kullanmasıdır. Bunun için C# 'daki Interlocked sınıfını kullanmamız önerildi.C# 'da kendi TaS-Lock'umu nasıl uygularım?

Şimdiye kadar bu bende ne, ama tutarsız yanıtlar sonuçlanıyor gibi görünmektedir:

public interface Lock 
{ 
    void Lock(); 
    void Unlock(); 
} 

public class C_Sharp_Lock : Lock 
{ 
    readonly Object myLock = new object(); 

    public void Lock() 
    { 
     Monitor.Enter(myLock); 
    } 

    public void Unlock() 
    { 
     Monitor.Exit(myLock); 
    } 
} 

public class Tas_Lock : Lock 
{ 
    int L = 0; 

    public void Lock() 
    { 
     while (0 == Interlocked.Exchange(ref L, 1)) { }; 
    } 

    public void Unlock() 
    { 
     Interlocked.Exchange(ref L, 0); 
    } 
} 

bilen var mı yanlış burada ne yapıyorum?

Düzenleme: Aşağıdaki bunu değiştirdik

: Kevin cevap olarak

public class Tas_Lock : Lock 
{ 
    int L = 0; 

    public void Lock() 
    { 
     while (0 == Interlocked.CompareExchange(ref L, 1, 0)) { }; 
    } 

    public void Unlock() 
    { 
     Interlocked.Exchange(ref L, 0); 
    } 
} 

Ancak bu hala tutarsız sonuçlar verir.

Düzenleme # 2: C# kilidine değişiklikler:

public class C_Sharp_Lock : Lock 
{ 
    readonly Object myLock = new object(); 
    bool lockTaken = false; 

    public void Lock() 
    { 
     Monitor.Enter(myLock, ref lockTaken); 
    } 

    public void Unlock() 
    { 
     if (lockTaken) 
      Monitor.Exit(myLock); 
    } 
} 
+0

yaptığı -in sınıf SpinLock. Kilit zaten alınmışsa değeri değiştiremezsiniz –

+0

Bu bir üniversite ödevi mi yoksa yaptığınız bir ders mi? Merak ediyorum :) – vtortola

+0

@vtortola Kolej ödevin bir parçası. – Heijmaaans

cevap

5

sana yolu Interlocked.CompareExchange eser yanlış anlıyorsun. Önceden sağlanan karşılaştırmaya, 'a eşitse ve bir önceki değeri döndürdüğünde, otomatik olarak bir değer değiştirir. Kısaca

, Interlocked.CompareExchange(ref L, 1, 0) olacaktır: L daha sonra 1 L ayarlanır ve önceki değer döndürür, 0'a eşit ise L 0

  • eşit olup olmadığını

    • ara (0)
    • L 0'a eşit değilse, o zaman önceki değeri döndürecektir (ve dolayısıyla 1'e eşit olduğu) (1)

    Oradan, ne yapmalıyım kadar döngü olduğunu Interlocked.CompareExchange, 0 değerini döndürür (bu, kilidin elde edildiği anlamına gelir).

    public class Tas_Lock 
    { 
        int L = 0; 
    
        public void Lock() 
        { 
         while (0 != Interlocked.CompareExchange(ref L, 1, 0)) { } 
        } 
    
        public void Unlock() 
        { 
         Interlocked.Exchange(ref L, 0); 
        } 
    } 
    

    Unutulmaması gereken iki nokta:

    • Interlocked.ExchangeUnlock bir yerini olabilir sizin kodda, sabit kod

      Interlocked.CompareExchange iken döner 0. bekliyoruz daha hızlı Volatile.Write (veya tartışmasız, basit bir yazma olsa bile)

    • Bir ödev için değilse, yerleşik kullanabilirsiniz Zaten bütün bu şeyler Sen Lock `in CompareExchange()` değil, Exchange kullanmaya gerek optimize edilmiş şekilde
  • +0

    Açıklama için teşekkürler! Bu onu düzeltti. Bunu nasıl kullanmalıyım şimdi anladım. – Heijmaaans

    +0

    Başka bir sorum var.Standart C# kilitleme uygulamam bazen bir istisna döndürüyor çünkü bir kilit kullanılmadığında monitor.Exit çıkmaya çalışıyor. Bunu düzeltmek için, alındığında gerçek bir boole ayarlayan Monitor.Enter yönteminin aşırı yüklenmesini kullanarak bir kilit alındığını kontrol etmek için bir boole ekledim. Ancak, şimdi parametrenin yanlış olarak başlatılması gerektiğini belirten bir argüman istisnası alıyorum. Değişikliğimi görebilmeniz için yayınımı düzenledim. – Heijmaaans

    +0

    @Heijmaaans Kilit açma sonunda lockTaken öğesini false değerine döndürdüğünüzden emin olun. –