SORU
30 EKİM 2008, PERŞEMBE


Neden lock(this) {...} kötü?

MSDN documentation diyor

public class SomeObject
{
  public void SomeOperation()
  {
    lock(this)
    {
      //Access instance variables
    }
  }
}

eğer örnek alenen erişilebilir eğer bir "sorun". Neden merak ediyorum? Kilit gerekenden daha uzun süre yapılacak diye mi? Yoksa daha sinsi bir sebep var mı?

CEVAP
30 EKİM 2008, PERŞEMBE


Başka bir nesne üzerinde bir kilit olabilir genellikle sizin kontrolünüz dışında olduğundan kilit ifadeleri this kullanım için kötü şeklidir.

Düzgün paralel operasyon planı için, özel bir bakıma Olası kilitlenme durumları dikkate alınmalı ve kilit giriş noktaları ve bilinmeyen sayıda olması bunu engellemektedir. Örneğin, nesne bir başvuru ile herhangi bir nesne tasarımcısı/yaratıcısı haberi olmadan kilitleyebilirsiniz. Bu çok kanallı çözümler karmaşıklığını artırır ve onların doğruluğu etkileyebilir.

Özel bir alan genellikle derleyici erişim kısıtlamaları zorlamak gibi daha iyi bir seçenek olduğunu ve kilitleme mekanizması saklanması. this kullanarak halka kilitleme uygulamanızın bir parçası açarak saklama ihlal ediyor. Belgelenmiş oldu sürece this kilit edinme olacak o da belli değil. O zaman bile, belgeleri bir sorunu önlemek için güvenerek alt-optimal.

Son olarak, lock(this) aslında nesne bir parametre olarak geçirilen değiştiren yaygın yanlış kanı vardır, ve salt okunur ya da erişilemez hale getirir. Buyanlış. Nesne lock parametre olarak geçirilen sadece bir olarak hizmet vermektediranahtar. Eğer bir kilit zaten anahtar üstünde tutuluyor, kilit yapılamaz; aksi halde, kilidi izin verilir.

Bu kötü değişmez ve/erişilebilir uygulama parçaları arasında paylaşılıyor beri lock tablolarda anahtarları dizeleri kullanmak nedeni budur. Özel bir değişken kullanmalısınız, Object bir örnek iyi olacaktır.

Aşağıdaki C çalışma# örnek kodu.

public class Person
{
    public int Age { get; set;  }
    public string Name { get; set; }

    public void LockThis()
    {
        lock (this)
        {
            System.Threading.Thread.Sleep(10000);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var nancy = new Person {Name = "Nancy Drew", Age = 15};
        var a = new Thread(nancy.LockThis);
        a.Start();
        var b = new Thread(Timewarp);
        b.Start(nancy);
        Thread.Sleep(10);
        var anotherNancy = new Person { Name = "Nancy Drew", Age = 50 };
        var c = new Thread(NameChange);
        c.Start(anotherNancy);
        a.Join();
        Console.ReadLine();
    }

    static void Timewarp(object subject)
    {
        var person = subject as Person;
        if (person == null) throw new ArgumentNullException("subject");
        // A lock does not make the object read-only.
        lock (person.Name)
        {
            while (person.Age <= 23)
            {
                // There will be a lock on 'person' due to the LockThis method running in another thread
                if (Monitor.TryEnter(person, 10) == false)
                {
                    Console.WriteLine("'this' person is locked!");
                }
                else Monitor.Exit(person);
                person.Age  ;
                if(person.Age == 18)
                {
                    // Changing the 'person.Name' value doesn't change the lock...
                    person.Name = "Nancy Smith";
                }
                Console.WriteLine("{0} is {1} years old.", person.Name, person.Age);
            }
        }
    }

    static void NameChange(object subject)
    {
        var person = subject as Person;
        if (person == null) throw new ArgumentNullException("subject");
        // You should avoid locking on strings, since they are immutable.
        if (Monitor.TryEnter(person.Name, 30) == false)
        {
            Console.WriteLine("Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string \"Nancy Drew\".");
        }
        else Monitor.Exit(person.Name);

        if (Monitor.TryEnter("Nancy Drew", 30) == false)
        {
            Console.WriteLine("Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!");
        }
        else Monitor.Exit("Nancy Drew");
        if (Monitor.TryEnter(person.Name, 10000))
        {
            string oldName = person.Name;
            person.Name = "Nancy Callahan";
            Console.WriteLine("Name changed from '{0}' to '{1}'.", oldName, person.Name);
        }
        else Monitor.Exit(person.Name);
    }
}

Konsol çıktı

'this' person is locked!
Nancy Drew is 16 years old.
'this' person is locked!
Nancy Drew is 17 years old.
Failed to obtain lock on 50 year old Nancy, because Timewarp(object) locked on string "Nancy Drew".
'this' person is locked!
Nancy Smith is 18 years old.
'this' person is locked!
Nancy Smith is 19 years old.
'this' person is locked!
Nancy Smith is 20 years old.
Failed to obtain lock using 'Nancy Drew' literal, locked by 'person.Name' since both are the same object thanks to inlining!
'this' person is locked!
Nancy Smith is 21 years old.
'this' person is locked!
Nancy Smith is 22 years old.
'this' person is locked!
Nancy Smith is 23 years old.
'this' person is locked!
Nancy Smith is 24 years old.
Name changed from 'Nancy Drew' to 'Nancy Callahan'.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BrandonHarrisWalker

    BrandonHarri

    27 Kasım 2006
  • Derek Banas

    Derek Banas

    12 AĞUSTOS 2008
  • Dom Esposito

    Dom Esposito

    26 Mayıs 2011