Yanıtlar:
Döndürme kilidi, paylaşılan bir kaynağın aynı anda iki veya daha fazla işlem tarafından değiştirilmesini önlemenin bir yoludur. Kaynağı değiştirmeye çalışan ilk işlem kilidi “alır” ve kaynakla yapması gerekeni yaparak yoluna devam eder. Daha sonra kilidi almaya çalışan diğer işlemler durdurulur; ilk işlem tarafından serbest bırakılması için kilidin, dolayısıyla da isimlendirme kilidinin beklediğinden "yerinde dönmesi" söylenir.
Linux çekirdeği, belirli bir çevre birimine veri gönderirken olduğu gibi birçok şey için döndürme kilitleri kullanır. Çoğu donanım çevre birimi birden fazla eşzamanlı durum güncellemesini ele almak için tasarlanmamıştır. İki farklı değişiklik yapılması gerekiyorsa, birinin diğerini kesin olarak takip etmesi gerekir, üst üste gelemezler. Döndürme kilidi, değişikliklerin bir defada yapılmasını sağlayarak gerekli korumayı sağlar.
Döndürme kilitleri bir sorundur, çünkü iş parçacığının CPU çekirdeğinin başka bir işlem yapmasını engelleyen dönen bloklar. Linux çekirdeği, altında çalışan kullanıcı alanı programlarına çok görevli hizmetler sunarken, bu genel amaçlı çok görevli hizmet birimi çekirdek kodunu kapsamaz.
Bu durum değişiyor ve Linux'un varoluşunun çoğu için var. Linux 2.0 aracılığıyla, çekirdek neredeyse tamamen tek bir görevli bir programdı: CPU, çekirdek kodu çalıştırırken, yalnızca bir CPU çekirdeği kullanıldı, çünkü Big Kernel Lock (BKL) adı verilen tüm paylaşılan kaynakları koruyan tek bir döndürme kilidi vardı. ). Linux 2.2'den başlayarak, BKL yavaş yavaş her biri daha odaklı bir kaynak sınıfını koruyan birçok bağımsız kilitlere bölünür. Bugün, çekirdek 2.6 ile BKL hala var, ancak sadece biraz daha ayrıntılı bir şekilde kilitlenemeyen gerçekten eski kodlar tarafından kullanılıyor. Artık çok çekirdekli bir kutunun her CPU'nun kullanışlı bir çekirdek kodu çalıştırması mümkün.
Linux çekirdeğinde genel çoklu görev eksikliğinden dolayı BKL'yi bölmenin faydasının bir sınırı var. Bir CPU çekirdeği bir çekirdek döndürme kilidinde dönmeyi engellerse, kilit serbest bırakılıncaya kadar başka bir şey yapmak için tekrar başlatılamaz. Sadece oturur ve kilit serbest bırakılıncaya kadar döner.
Döndürme kilitleri, eğer iş yükü her çekirdeğin daima tek bir döndürme kilidini beklemesini bekliyorsa, 16 çekirdekli bir kutuyu tek çekirdekli bir kutuya etkili bir şekilde döndürebilir. Bu, Linux çekirdeğinin ölçeklenebilirliği için ana sınırdır: CPU çekirdeğini 2'den 4'e iki katına çıkarmak, muhtemelen Linux kutusunun hızını iki katına çıkaracaktır, ancak 16'dan 32'ye iki katına çıkması, çoğu iş yüküyle muhtemelen iki katına çıkmayacaktır.
Döndürme kilidi, bir işlemin sürekli olarak bir kilidin kaldırılması için yoklamasıdır. Kötü kabul edilir çünkü işlem (genellikle) gereksiz yere döngü tüketir. Linux'a özgü değil, genel bir programlama şeklidir. Ve genel olarak kötü bir uygulama olarak kabul edilirken, aslında doğru çözümdür; Zamanlayıcının kullanım maliyetinin (CPU çevrimleri açısından), dönme kilidinin dayanması beklenen birkaç çevrimin maliyetinden daha yüksek olduğu durumlar vardır.
Spinlock örneği:
#!/bin/sh
#wait for some program to clear a lock before doing stuff
while [ -f /var/run/example.lock ]; do
sleep 1
done
#do stuff
Sıkma kilidini önlemenin sık bir yolu vardır. Bu özel örnek için, inotifywait adında bir Linux aracı var (genellikle varsayılan olarak yüklenmemiş). C dilinde yazılmışsa , Linux'un sağladığı inotify API'sini kullanırsınız .
Aynı örnek, inotifywait kullanarak aynı şeyin döndürme kilidi olmadan nasıl başarılacağını gösterir:
#/bin/sh
inotifywait -e delete_self /var/run/example.lock
#do stuff
Bir iş parçacığı bir kilit elde etmeye çalıştığında, başarısız olursa üç şey olabilir, deneyebilir ve engelleyebilir, deneyebilir ve devam edebilir, daha sonra bir olay meydana geldiğinde işletim sistemine uyanmasını söyleyerek uykuya dalabilir.
Şimdi bir dene ve devam et, dene ve engelle işleminden daha az zaman harcıyor. Diyelim ki bir "dene ve devam et" in bir zaman alacağını ve bir "dene ve engelle" nin yüz alacağını söyleyelim.
Şimdi bir an için bir dişlinin kilidi tutan 4 birim zaman alacağını varsayalım. 100 ünite beklemek çok zararlıdır. Bunun yerine "dene ve devam et" döngüsünü yazarsınız. Dördüncü denemede genellikle kilidi alırsınız. Bu bir döndürme kilidi. Buna dişlinin kilitlenene kadar yerinde dönmeye devam etmesi denir.
Ek bir güvenlik önlemi, döngünün çalışma sayısını sınırlamaktır. Örnekte altı kez for döngüsü çalıştırıyorsunuz, örneğin altı kez, başarısız olursa o zaman "dene ve engelle" olur.
Bir ipliğin her zaman kilidini 200 birim için tutacağını biliyorsanız, o zaman her deneme için bilgisayar zamanını boşa harcar ve devam ettirirsiniz.
Bu yüzden sonunda, bir döndürme kilidi çok verimli ya da boşa harcanabilir. Bir kilidi tutma "tipik" süresinin "denemek ve engellemek" için geçen süreden daha yüksek olması ziyan olur. Bir kilit tutma için tipik zaman, 'deneme ve bloklama' zamanından daha küçük olduğunda etkilidir.
Not: Eğer hala okuyabiliyorsanız, kitap okumak için kitap "A Thread Primer" dır.
Bir kilit senkronize etmek için iki veya daha fazla görevler (süreçler, iplikler) için bir yöntemdir. Özellikle, her iki görev de aynı anda yalnızca bir görev tarafından kullanılabilecek bir kaynağa aralıklı erişime ihtiyaç duyduğunda, bu görevlerin kaynağı aynı anda kullanmamaları için düzenlemelerinin bir yoludur. Kaynağa erişmek için, bir görev aşağıdaki adımları gerçekleştirmelidir:
take the lock
use the resource
release the lock
Başka bir görev daha önce almışsa, kilit almak mümkün değildir. (Kilidi fiziksel belirteçli bir nesne olarak düşünün. Nesne bir çekmecede veya birisinin elinde var. Sadece nesneyi tutan kişi kaynağa erişebilir.) Yani “kilidi al” gerçekten “bekleyin” başka kimsede kilit yok, sonra al ”.
Üst düzey bir bakış açısıyla, kilitleri uygulamanın iki ana yolu vardır: sıkma kilitleri ve koşullar. İle spinlocks öğle vakti kadar sadece “eğirme” (yani bir döngüde hiçbir şey yapmadan) kilit araçları alarak başka kilidi vardır. Koşullarla, bir görev kilidi almaya çalışırsa, ancak başka bir görevde bulunduğundan engellenirse, yeni gelen bir bekleme kuyruğuna girer; serbest bırakma işlemi, kilidin mevcut olduğuna dair herhangi bir bekleyen göreve işaret eder.
(Bu açıklamalar kilit uygulamanıza izin vermek için yeterli değildir, çünkü atomiklik hakkında hiçbir şey söylemedim. Ama atomiklik burada önemli değil.)
Döndürme kilitleri açık bir şekilde israflıdır: bekleme görevi kilidin alıp almadığını kontrol etmeye devam eder. Peki neden ve ne zaman kullanılıyor? Kilit tutulmadığı durumlarda sıkma kilitleri elde etmek genellikle çok ucuzdur. Bu, kilitlenme şansı küçük olduğunda çekici kılar. Ayrıca, kilitleme kilitleri yalnızca kilidi edinmenin uzun sürmesi beklenmiyorsa uygulanabilir durumdadır. Bu yüzden spinlocklar çok kısa bir süre boyunca tutulacakları durumlarda kullanılmaya meyillidir, bu nedenle çoğu denemenin ilk denemede başarılı olması beklenir ve beklemesi gerekenler uzun süre beklemez.
Linux Aygıt Sürücüleri bölümünde , spinlock'ların ve Linux çekirdeğinin diğer eşzamanlılık mekanizmalarının iyi bir açıklaması vardır , bölüm 5.
synchronized
bir spinlock tarafından uygulanacağından şüpheliyim : bir synchronized
blok çok uzun süre çalışabilir. synchronized
Daha büyük senkronizasyon ilkelleri oluşturmak için bir ilkel değil, bazı durumlarda kilitlerin kullanımını kolaylaştıran bir dil yapısıdır.
Döndürme kilidi, zamanlayıcıyı devre dışı bırakarak çalışan ve muhtemelen kilidin alındığı o çekirdekte kesin olan (irqsave varyantı) kesen bir kilittir. Planlamayı devre dışı bırakmadaki bir muteksten farklıdır, böylece döndürme kilidi tutulurken yalnızca ipliğiniz çalışabilir. Bir muteks, tutulurken diğer yüksek öncelikli konuların programlanmasına izin verir, fakat korunan kısmı aynı anda yürütmelerine izin vermez. Döndürme kilitleri çoklu görevi devre dışı bıraktığından, döndürme kilidini alamaz ve ardından bir muteks almaya çalışacak başka bir kod çağırabilirsiniz. Döndürme bölümü içindeki kodunuz asla uyumamalıdır (kod, kilitlenmiş bir muteks veya boş bir semaforla karşılaştığında genellikle uyur).
Bir muteks ile diğer bir fark, dişlilerin tipik olarak bir muteks için sıraya girmesidir, bu yüzden altındaki bir muteksin bir kuyruğu vardır. Oysa spinlock sadece olması gerekse bile başka hiçbir ipliğin çalışmamasını sağlar. Bu nedenle, dosyanızın dışındaki işlevleri uyuyamayacağından emin olduğunuzda çağırırken hiçbir zaman bir kilit tutmamanız gerekir.
Dönme kilidinizi bir kesme ile paylaşmak istediğinizde irqsave varyantını kullanmanız gerekir. Bu sadece zamanlayıcıyı devre dışı bırakmakla kalmayacak aynı zamanda kesintileri de devre dışı bırakacaktır. Mantıklı geliyor mu? Spinlock, başka hiçbir şeyin çalışmayacağından emin olarak çalışır. Bir ara vermek istemiyorsanız, onu devre dışı bırakın ve kritik bölüme güvenle devam edin.
Çok çekirdekli bir makinede, bir döndürme kilidi, kilidi açmak için kilidi tutan başka bir çekirdeği bekleyerek aslında dönecektir. Bu eğirme sadece çok çekirdekli makinelerde gerçekleşir, çünkü tek çekirdekli makinelerde gerçekleşemez (eğirme kilidini tutarsınız ve devam edersiniz veya kilit serbest bırakılıncaya kadar asla koşmazsınız).
Spinlock anlamlı olduğu yerde israf yapmaz. Çok küçük kritik bölümler için, zamanlayıcıyı önemli işi bitirmek için gereken birkaç mikrosaniye askıya almanın bir muteks görev sırasını ayırmak israf olur. Kilidi bir io işlemi sırasında (uykuya dalabilir) uyumanız veya tutmanız gerekirse, bir muteks kullanın. Kesinlikle bir dönüş kilidini kesinlikle kilitlemeyin ve ardından bir kesme işleminde serbest bırakmayı deneyin. Bu çalışacak olsa da, bir süre arduino saçmalığı gibi olacak (flagnotset); Bu durumda bir semafor kullanın.
Bellek işlem blokları için basit bir karşılıklı dışlamaya ihtiyaç duyduğunuzda bir asma kilit alın. Bir muteks kilitlemeden hemen önce birden fazla iş parçacığının durmasını istediğinizde bir muteks alın ve ardından muteks serbest olduğunda ve aynı iş parçacığında kilitlediğinizde ve bıraktığınızda devam etmek için seçilecek en yüksek öncelikli iş parçacığını alın. Bir iş parçacığı ya da bir kesme olarak göndermek ve başka bir iş parçacığına almak niyetinde bir semafor kapmak. Karşılıklı dışlamayı sağlamanın üç farklı yolu var ve bunlar biraz farklı amaçlar için kullanılıyor.