C # 'da yeniden giriş kilitleri


119

Aşağıdaki kod .NET üzerinde C # kullanarak kilitlenmeye neden olur mu?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }

6
Bu sorunun başlığını değiştirmeyi düşünebilir miyiz - belki de yakın zamanda kapatılmış gibi bir şeyle İç içe geçmiş kilitler neden kilitlenmeye neden olmaz? Mevcut haliyle, başlık neredeyse insanların onu keşfetmesini engellemek için tasarlanmış gibi görünüyor.
Jeff Sternal

12
Aslında bunu 'evresel' arama sözcüğüne dayanarak buldum ve sorumu yanıtladı.
Yinelenen bir soruysa

@JeffSternal yorumuna katılıyorum, bu soru soruyu arayan kişinin zaten "Yeniden giriş" kilitlerine aşina olduğunu varsayar. Başka bir tekrar sorusunun bunun için iyi bir başlığı olduğunu düşünüyorum: stackoverflow.com/questions/3687505/…
Luis Perez

Yanıtlar:


148

Hayır, aynı nesneye kilitlendiğin sürece. Özyinelemeli kod etkin bir şekilde zaten kilide sahiptir ve böylece engellenmeden devam edebilir.

lock(object) {...}Monitor sınıfını kullanmanın kısaltmasıdır . As Marc işaret , Monitorizin verir yeniden entrancy böylece bir nesne üzerinde kilit girişimleri tekrarlanan, geçerli iş parçacığı zaten kilit var hangi sadece ceza çalışacaktır.

Farklı nesnelere kilitlenmeye başlarsanız , o zaman dikkatli olmanız gerekir. Şunlara özellikle dikkat edin:

  • Her zaman belirli sayıda nesnede aynı sırayla kilit alın.
  • Kilitleri her zaman nasıl elde ettiğinize göre ters sırada serbest bırakın .

Bu kurallardan herhangi birini ihlal ederseniz , bir noktada kilitlenme sorunları yaşayacağınız hemen hemen garantidir .

NET'te iş parçacığı senkronizasyonunu açıklayan iyi bir web sayfası: http://dotnetdebug.net/2005/07/20/monitor-class-avoiding-deadlocks/

Ayrıca, bir seferde mümkün olduğunca az nesneyi kilitleyin. Mümkünse iri taneli kilitler uygulamayı düşünün . Buradaki fikir, kodunuzu bir nesne grafiği olacak şekilde yazabiliyorsanız ve bu nesne grafiğinin kökünde kilitler elde edebiliyorsanız, o zaman bunu yapın. Bu, o kök nesnede bir kilidiniz olduğu ve bu nedenle kilitleri elde ettiğiniz / bıraktığınız sıra hakkında çok fazla endişelenmenize gerek olmadığı anlamına gelir.

(Bir not daha, örneğiniz teknik olarak özyinelemeli değildir. Özyinelemeli Bar()olması için, tipik olarak bir yinelemenin parçası olarak kendisini çağırması gerekir.)


1
Özellikle farklı dizilerde.
Marc Gravell

6
Yeniden özyineleme; aslında; Guy lehine, terim yeniden giriliyor
Marc Gravell

Terminolojiyle ilgili açıklama için teşekkürler - Soruyu düzenledim ve düzelttim.
Guy

Bu soru oldukça dikkat çekiyor gibi görünüyor, bu yüzden cevabımı, ilk yazdığımdan beri bulduğum birkaç başka notla güncelledim.
Neil Barnwell

Aslında, kilitleri açma sırasının önemli olduğunu sanmıyorum. Bunları seçtiğiniz sıra kesinlikle geçerlidir, ancak kilidi serbest bırakmak herhangi bir şeye bağlı olmadığı sürece (istediğiniz zaman serbest bırakabilirsiniz), edindiğiniz tüm kilitleri serbest bıraktığınız sürece sorun yaşamazsınız.
bobroxsox

20

Eh, Monitoro yapmamalı: Kendini kilitlenmeye edemez çok ... çok hayır, re-entrancy verir


7

Bir iplik zaten bir kilit tutuyorsa, kendini bloke etmeyecektir. .Net çerçevesi bunu sağlar. Yalnızca, iki iş parçacığının, hangi kod yolları olursa olsun aynı iki kilidi sıra dışı elde etmeye çalışmadığından emin olmanız gerekir.

Aynı iş parçacığı aynı kilidi birden çok kez alabilir, ancak kilidi aldığınızla aynı sayıda açtığınızdan emin olmalısınız. Elbette, bunu gerçekleştirmek için "kilit" anahtar sözcüğünü kullandığınız sürece, bu otomatik olarak gerçekleşir.


Bunun monitörler için doğru olduğunu, ancak diğer kilit türleri için gerekli olmadığını unutmayın.
Jon Skeet

(Bunu bilmediğinizi ima etmek istemiyorum tabii ki - sadece bu önemli bir ayrım :)
Jon Skeet

İyi bir noktaya değindin. Aslında baştan sona "kilidi" "monitör" olarak değiştirecektim ama sonra dikkatim dağıldı. Ve tembel. Ve davranış aynı zamanda Windows mutex kernal nesneleri için de geçerlidir, bu yüzden yeterince yakın olduğunu düşündüm!
Jeffrey L Whitledge

5

Hayır, bu kodda ölü kilitler olmayacak. En basit kilitlenmeyi gerçekten yaratmak istiyorsanız, en az 2 kaynak gerektirir. Köpek ve kemik senaryosunu düşünün. 1. Bir köpek 1 kemik üzerinde tam kontrole sahiptir, bu nedenle diğer köpekler beklemek zorundadır. 2. Sırasıyla kemiklerini kilitlediklerinde ve başkalarının da kemiklerini aradıklarında, 2 kemikli 2 köpeğin bir kilitlenme yaratması gerekir.

.. daha karmaşık kilitlenmelere neden olan köpek ve kemiklerde böyle devam eder.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.