Linux'ta spinlock nedir?


32

Linux spinlockları hakkında detaylı bilgi almak istiyorum; Birileri onları bana açıklayabilir mi?

Yanıtlar:


34

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.


@Warren: Birkaç şüphe- Bu Big Kernel Lock ve bunun etkileri hakkında daha fazla bilgi edinmek istiyorum. Ayrıca son işlemci
Sen

2
Re: BKL'nin çıkarımları: Bunu açıkça ifade ettiğimi düşündüm. Çekirdekte yalnızca bir kilit bulunduğunda, iki çekirdek BKL tarafından korunan bir şey yapmaya çalıştığında, bir çekirdek korunan kaynağını kullanarak bitirirken bir çekirdek engellenir. Kilitleme ne kadar iyi ayarlanmışsa, bunun gerçekleşmesi olasılığı o kadar düşük olur, bu nedenle işlemci kullanımı artar.
Warren Young,

2
Re: iki katına: Bir bilgisayara işlemci çekirdeği eklerken azalan getirilerin bir kanunu var demek istiyorum. Çekirdek sayısı arttıkça, iki veya daha fazlasının belirli bir kilitle korunan bir kaynağa erişmesi gerekme olasılığı da artar. Kilit granülerliğinin arttırılması, bu tür çarpışmaların şansını azaltır, ancak çok fazla ekleme yapmanın da tepkisi vardır. Bunu bugünlerde sıklıkla binlerce işlemciye sahip olan süper bilgisayarlarda kolayca görebilirsiniz: çoğu iş yükü onlar için yetersizdir, çünkü ortak kaynak çekişmesi nedeniyle birçok işlemciyi boşa harcayamazlar.
Warren Young,

1
Bu ilginç bir açıklama olsa da (bunun için +1), spinlock ve diğer kilit çeşitleri arasındaki farkı aktarmanın etkili olduğunu sanmıyorum.
Gilles 'SO- kötülük' dur '22

2
Bir döndürme kilidi ile bir semafor arasındaki farkı bilmek isterse, bu farklı bir soru. Bir başka iyi ama teğetsel soru, spin kodunu, bir muteks gibi kullanıcı kodunda daha yaygın olan bir şey yerine iyi seçimleri kilitleyen Linux çekirdeği tasarımı ile ilgili olan şeydir. Bu cevap, olduğu gibi bolca ayrılmaktadır.
Warren Young

11

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

Zamanlayıcının oradaki rolü nedir? Veya herhangi bir rolü var mı?
Sen

1
Döndürme kilidi yönteminde, zamanlayıcı, görevini yerine getirmek için her ~ 1 saniyede bir işlemi sürdürür (bu yalnızca bir dosyanın varlığını denetler). İnotifywait örneğinde, zamanlayıcı yalnızca alt süreç (inotifywait) çıktığında devam eder. Inotifywait da uyuyor; Zamanlayıcı yalnızca inotify olayı gerçekleştiğinde devam eder.
Shawn J. Goff

Peki bu senaryo tek çekirdekli işlemci sisteminde nasıl ele alınmaktadır?
Sen

@Sen: Bu, Linux Aygıt Sürücülerinde oldukça iyi açıklanmıştır .
Gilles 'SO- kötülük' dur '22

1
Bu bash betiği, spinlock için kötü bir örnek. Süreci uykuya sokmak için duraklatıyorsunuz. Bir spinlock asla uyumaz. Tek çekirdekli bir makinede programlayıcıyı askıya alır ve devam eder (meşgul beklemeden)
Martin

7

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.


iplik kilitleninceye kadar yerine dönmeye devam eder . Lütfen bana bu dönüşün ne olduğunu söyler misiniz? Bu, wait_queue'ye gelip, Zamanlayıcı tarafından yürütülmek üzere mi? Belki düşük seviyeye girmeye çalışıyorum ama yine de şüphelerimi tutamıyorum.
Sen

Temel olarak, döngü içinde 3-4 talimatları arasında dönerek.
Paul Stelian

5

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.


Diğer senkronizasyon ilkellerini uygulamak için iyi bir yol nedir? Bir döndürme kilidi alın, bir başkasının gerçekleştirilmekte olup olmadığını kontrol edin, sonra zamanlayıcıyı kullanın veya erişim izni verin? Java'da synchronized () bloğunu bir döndürme kilidi biçimi olarak görebilir miyiz ve doğru bir şekilde uygulanmış ilkellerde yalnızca bir döndürme kilidi kullanabilir miyiz?
Paul Stelian

@PaulStelian Bu şekilde "yavaş" kilitler uygulamak gerçekten yaygındır. Bu kısmı yanıtlayacak kadar Java bilmiyorum, ancak bunun synchronizedbir spinlock tarafından uygulanacağından şüpheliyim : bir synchronizedblok çok uzun süre çalışabilir. synchronizedDaha 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.
Gilles 'SO- kötülükten vazgeç'

3

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.

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.