Spinlock ve Semafor


119

Bir semafor ve döndürme kilidi arasındaki temel farklar nelerdir?

Döndürme kilidi yerine semaforu ne zaman kullanırız?

Yanıtlar:


134

Spinlock ve semafor temel olarak dört şeyde farklılık gösterir:

1. Ne oldukları
Bir spinlock , olası bir kilit uygulamasıdır, yani meşgul bekleme ("döndürme") ile gerçekleştirilen bir uygulamadır. Bir semafor, bir kilidin bir genellemesidir (veya tam tersi, bir kilit, semaforun özel bir durumudur). Genellikle, ancak zorunlu olmamakla birlikte , spinlock'lar yalnızca bir süreç içinde geçerlidir, oysa semaforlar da farklı işlemler arasında senkronize etmek için kullanılabilir.

Bir kilit karşılıklı dışlama için çalışır, yani her seferinde bir iş parçacığı kilidi alabilir ve kodun "kritik bölümü" ile devam edebilir. Genellikle bu, birkaç iş parçacığı tarafından paylaşılan bazı verileri değiştiren kod anlamına gelir.
Bir semaforun bir sayacı vardır ve kendisine gönderdiğiniz değere ve (bazı uygulamalarda) izin verilen maksimum değerinin ne olduğuna bağlı olarak bir veya birkaç iş parçacığı tarafından elde edilmesine izin verir .

Dolayısıyla, bir kilit, maksimum 1 değerine sahip bir semaforun özel bir durumu olarak düşünülebilir.

2. Ne yaparlar
Yukarıda belirtildiği gibi, spinlock bir kilittir ve bu nedenle karşılıklı bir dışlama (kesinlikle 1'e 1) mekanizmasıdır. Genellikle atomik bir şekilde bir bellek konumunu tekrar tekrar sorgulayarak ve / veya değiştirerek çalışır. Bu, bir spinlock edinmenin, CPU döngülerini uzun süre (belki sonsuza kadar) yakarken, etkin bir şekilde "hiçbir şey" elde etmeyen "meşgul" bir işlem olduğu anlamına gelir.
Böyle bir yaklaşım için ana teşvik, bir bağlam anahtarının birkaç yüz (veya belki bin) kez döndürmeye eşdeğer bir ek yüke sahip olmasıdır, bu nedenle, birkaç döngü döndürerek yakılarak bir kilit elde edilebilirse, bu genel olarak çok iyi olabilir. daha verimli. Ayrıca, gerçek zamanlı uygulamalar için, planlayıcının ileride çok uzak bir zamanda onlara geri gelmesini engellemek ve beklemek kabul edilemez.

Bir semafor, tersine, ya hiç dönmez ya da çok kısa bir süre için döner (sistem çağrısı ek yükünden kaçınmak için bir optimizasyon olarak). Bir semafor elde edilemezse, çalıştırılmaya hazır farklı bir iş parçacığına CPU zamanını vererek bloke eder. Bu, elbette, iş parçacığınızın tekrar programlanmasından önce birkaç milisaniyenin geçtiği anlamına gelebilir, ancak bu sorun değilse (genellikle değildir), o zaman çok verimli, CPU-tutucu bir yaklaşım olabilir.

3. Tıkanıklık durumunda nasıl davranırlar
Spinlock'ların veya kilitsiz algoritmaların "genellikle daha hızlı" olduğu veya yalnızca "çok kısa görevler" için yararlı oldukları (ideal olarak, hiçbir senkronizasyon nesnesi daha uzun süre tutulmamalıdır) yaygın bir yanılgıdır. kesinlikle gerekenden daha fazla).
Tek önemli fark, farklı yaklaşımların tıkanıklık varlığında nasıl davrandığıdır .

İyi tasarlanmış bir sistemde normalde düşük veya hiç tıkanıklık yoktur (bu, tüm iş parçacıkları aynı anda kilidi almaya çalışmadığı anlamına gelir). Örneğin, bir Her zamanki olup son olarak ağı, şifresini çözer gelen yükler daha sonra, fermuar-sıkıştırılmış veri yarım megabayt bir kilidi alır ve verileri ayrıştırır ve yazma kodu (bir kaba ekleme verileri, vs.) ortak bir referans değiştirir kilidi açmadan önce. Bunun yerine, kilit yalnızca paylaşılan kaynağa erişim amacıyla elde edilecektir .
Bu, kritik bölümün dışında, içinde olduğundan önemli ölçüde daha fazla iş olduğu anlamına geldiğinden, doğal olarak, bir dişin kritik bölümün içinde olma olasılığı nispeten düşüktür ve bu nedenle, aynı anda çok az diş, kilit için rekabet halindedir. Tabii ki her şimdi ve sonra da iki parçacığı (bu eğer aynı anda kilidi almak için çalışacağız olamazdı ! Eğer bir kilit gerek olmazdı olur), fakat bu daha ziyade bir "sağlıklı" sisteminde kural daha istisna .

Böyle bir durumda, spinlock semafordan büyük ölçüde daha iyi performans gösterir çünkü kilit tıkanıklığı yoksa spinlock edinmenin ek yükü, bir bağlam anahtarı için yüzlerce / binlerce döngü veya kaybetmek için 10-20 milyon döngü ile karşılaştırıldığında yalnızca bir düzine döngüdür. bir zaman diliminin geri kalanı.

Öte yandan, yüksek tıkanıklık göz önüne alındığında veya kilit uzun süre tutulursa (bazen yardım edemezsiniz!), Bir spinlock hiçbir şey elde etmek için çılgın miktarda CPU döngüsü yakacaktır.
Bir semafor (veya muteks) bu durumda çok daha iyi bir seçimdir, çünkü bu süre boyunca farklı bir iş parçacığının yararlı görevleri çalıştırmasına izin verir . Veya başka hiçbir iş parçacığının yapacak yararlı bir şeyi yoksa, işletim sisteminin CPU'yu kısmasına ve ısıyı azaltmasına / enerji tasarrufu yapmasına izin verir.

Ayrıca, tek çekirdekli bir sistemde, eğirme ipliği, muhtemelen gerçekleşemeyecek bir durum değişikliğini bekleyerek tüm zamanını boşa harcayacağından (serbest bırakma ipliği planlanana kadar, ki bu da değil) kilit tıkanıklığı varlığında oldukça verimsiz olacaktır. Bekleyen iş parçacığı çalışırken olmuyor !). Bu nedenle, herhangi bir miktarda çekişme göz önüne alındığında , kilidi elde etmek en iyi durumda yaklaşık 1 1/2 zaman dilimi alır (serbest bırakma iş parçacığının bir sonraki planlanmakta olduğunu varsayarsak), bu çok iyi bir davranış değildir.

4. Nasıl uygulandıkları
Günümüzde bir semafor tipik olarak sys_futexLinux altında sarmalanacaktır (isteğe bağlı olarak birkaç denemeden sonra çıkan bir spinlock ile).
Spinlock, tipik olarak atomik işlemler kullanılarak ve işletim sistemi tarafından sağlanan hiçbir şey kullanılmadan uygulanır. Geçmişte bu, ya derleyici içsellerini ya da taşınabilir olmayan derleyici talimatlarını kullanmak anlamına geliyordu. Bu arada, hem C ++ 11 hem de C11, dilin bir parçası olarak atomik işlemlere sahiptir, bu nedenle, kanıtlanabilir şekilde doğru kilitsiz kod yazmanın genel zorluğunun yanı sıra, artık tamamen taşınabilir ve (neredeyse) kilitsiz kodu uygulamak mümkündür. ağrısız yol.


"Ayrıca, tek çekirdekli bir sistemde, eğirme ipliği, gerçekleşmesi mümkün olmayan bir durum değişikliğini bekleyerek tüm zamanını boşa harcayacağından, kilit tıkanıklığı durumunda bir spinlock oldukça verimsiz olacaktır": ayrıca (en azından Linux'ta ) spin_trylockKilit alınamazsa, hemen bir hata kodu ile dönen. Döndürme kilidi her zaman o kadar sert değildir. Ancak kullanmak spin_trylock, bir uygulamanın bu şekilde düzgün bir şekilde tasarlanmasını gerektirir (muhtemelen bekleyen işlemlerden oluşan bir sıra ve burada, bir sonrakini seçerek, gerçek olanı kuyrukta bırakarak).
Hibou57

Muteksleri ve semaforları engellemek yalnızca tek iş parçacıklı ortamlarda yararlı değildir, aynı zamanda aşırı abonelik varsa, yani bir programın (veya sistemi paylaşan birden çok programın) oluşturduğu iş parçacığı sayısı donanım kaynaklarının sayısından daha fazladır. Bu gibi durumlarda, iş parçacığınızı bloke etmek, diğerlerinin CPU zamanını kullanışlı bir şekilde kullanabilmesini sağlar. Ek olarak, donanım hiper iş parçacığını destekliyorsa, diğer iş parçacığı boş döngüyü gerçekleştirmek için kullanılan yürütme birimlerinden yararlanabilir.
Jorge Bellon

76

basitçe, bir semafor, "verimli" bir senkronizasyon nesnesidir, bir spinlock, "meşgul bekleme" olandır. (Bir kod bölgesini tek bir iş parçacığından koruyan bir muteks veya koruma veya monitör veya kritik bölümden farklı olarak, birkaç iş parçacığını senkronize etmelerinden dolayı semaforlardan biraz daha fazlası vardır)

Daha fazla durumda semafor kullanırsınız, ancak çok kısa bir süre için kilitleyeceğiniz bir spinlock kullanırsınız - özellikle çok fazla kilitlerseniz kilitlemenin bir maliyeti vardır. Bu gibi durumlarda, korunan kaynağın kilidinin açılmasını beklerken bir süre spinlock yapmak daha verimli olabilir. Açıkçası, çok uzun süre dönerseniz bir performans düşüşü var.

tipik olarak bir iplik kuantumundan daha uzun süre dönüyorsanız, bir semafor kullanmalısınız.


27

Yoav Aviram ve gbjbaanb'ın söylediklerinin üzerinde ve ötesinde, diğer önemli nokta, tek CPU'lu bir makinede asla döndürme kilidi kullanmayacağınızdı, oysa bir semafor böyle bir makinede mantıklı olurdu. Günümüzde, çok çekirdekli, hiper iş parçacığı veya eşdeğeri olmayan bir makine bulmak için sık sık zorlanıyorsunuz, ancak tek bir CPU'nuzun olduğu durumlarda semafor kullanmalısınız. (Sebebin açık olduğuna inanıyorum. Tek bir CPU başka bir şeyin dönme kilidini serbest bırakmasını beklemekle meşgulse, ancak tek CPU'da çalışıyorsa, mevcut işlem veya iş parçacığı tarafından önlenene kadar kilidin serbest bırakılması olası değildir. O / S, biraz zaman alabilir ve önleme gerçekleşene kadar yararlı hiçbir şey olmaz.)


7
Tek dişli sistemlerde spinlock kullanmamanın ne kadar önemli olduğunu ikinci kez söylemek isterim. Öncelikli ters çevirme problemleri için işaretlidirler. Ve güven bana: Bu tür hataları ayıklamak istemezsiniz.
Nils Pipenbrinck

2
Bir veya daha fazla CPU'nuz olup olmadığına bakılmaksızın, spinlock'lar Linux çekirdeğinde her yerde bulunur. Tam olarak ne demek istiyorsun?
Prof. Falken

@ Kabul edilebilir: Tanımı gereği spinlock, CPU'daki mevcut iş parçacığının kilitli nesneyi serbest bırakmak için başka bir şeyin beklediği anlamına gelir. Kilidi değiştirebilecek tek aktif şey mevcut CPU ise, kilit döndürülerek çözülmeyecektir. Başka bir şey varsa - bir DMA aktarımı veya başka bir G / Ç denetleyicisi kilidi serbest bırakabilir, hepsi iyi ve iyi. Ancak başka hiçbir şey kilidi açamadığında döndürmek çok mantıklı değildir - CPU'yu şimdi başka bir işleme bırakabilir ve önlenmeyi bekleyebilirsiniz.
Jonathan Leffler

1
Çok iyi yanılıyor olabilirim, ancak yeniden giren (tek CPU) bir Linux çekirdeğinin çalışan bir döndürme kilidini kesintiye uğratabileceği izlenimine kapılmıştım.
Prof. Falken

2
@Amigable: Benim de yanılma ihtimalim var, ama sanırım spinlock'un klasik tanımına yakınım. Önleyici programlamayla, bir süreç, zaman diliminin sonuna kadar veya bir kesinti, dönme kilidinin kilitlenmesine izin veren koşulu sağlaması gerekiyorsa, bir kilit üzerinde dönebilir. tek bir CPU makinesinde iyi fikir. Üzerinde çalıştığım sistemde spinlock'lar var ve meşgul olmayan bekleme moduna geçmeden önce dönüş sayısı konusunda yapılandırılabilir bir üst sınır var. Bu, kullanıcı düzeyinde bir döndürme kilididir; çekirdekte bir fark olabilir.
Jonathan Leffler

19

Rubinni'nin Linux Aygıt Sürücülerinden

Semaforların aksine spinlocklar, kesme işleyicileri gibi uyuyamayan kodlarda kullanılabilir.


8

Çekirdek uzmanı değilim ama işte birkaç nokta:

Çekirdeği derlerken çekirdek hazırlığı etkinleştirilmişse, tek işlemcili makine bile döndürme kilitleri kullanabilir. Kernel preemption devre dışı bırakılırsa spin-lock (belki) bir void ifadesine genişler .

Ayrıca, Semafor ile Spin-lock'u karşılaştırmaya çalışırken, semaforun çekirdekte kullanılana atıfta bulunduğuna inanıyorum - IPC (kullanıcı alanı) için kullanılanı DEĞİL.

Temel olarak, kritik bölüm küçükse (uyku / uyanma ek yükünden daha küçükse) ve kritik bölüm uyuyabilen hiçbir şey çağırmıyorsa döndürme kilidi kullanılacaktır! Kritik bölüm daha büyükse ve uyuyabiliyorsa semafor kullanılmalıdır.

Raman Chalotra.


7

Spinlock, makineye bağlı montaj talimatlarını (test ve set gibi) kullanan bir dişler arası kilit uygulamasını ifade eder. İplik kilidi olarak adlandırılır çünkü iş parçacığı kilit kullanılabilir hale gelene kadar (meşgul bekleme) tekrar tekrar kontrol ederek bir döngüde bekler ("döner"). Spinlock'lar, işletim sistemleri (CPU değil) tarafından sağlanan bir tesis olan mutekslerin yerine kullanılır, çünkü spinlock'lar kısa bir süre kilitlendiklerinde daha iyi performans gösterirler.

Semafor, IPC için işletim sistemleri tarafından sağlanan bir tesistir, bu nedenle ana amacı süreçler arası iletişimdir. İşletim sistemi tarafından sağlanan bir tesis olarak performansı, dinler arası kilitleme için bir spinlock kadar iyi olmayacaktır (mümkün olsa da). Semaforlar daha uzun süre kilitlemek için daha iyidir.

Bununla birlikte, splinlock'ların montajda uygulanması zordur ve taşınabilir değildir.


4
Tüm çok iş parçacıklı CPU'lar bir spinlock talimatına ("test et ve ayarla") ihtiyaç duyar ve bu her zaman donanımda tek bir talimat olarak uygulanır çünkü aksi takdirde her zaman birden fazla iş parçacığının korumalı kaynağa "sahip olduğunu" düşündüğü bir yarış koşulu olurdu.
Richard T


POSIX, evreler tarafından paylaşılan bir semafor ile süreçler tarafından paylaşılan bir semafor arasında bir ayrım yapar.
Greg Rogers

2
Semaforlar süreçler arası senkronizasyon içindir, iletişim için değil.
Johan Bezem

6

Gözlemlerimi eklemek istiyorum, daha genel ve çok Linux'a özgü değil.

Bellek mimarisine ve işlemci yeteneklerine bağlı olarak, çok çekirdekli veya çok işlemcili bir sistemde semafor uygulamak için bir dönme kilidine ihtiyacınız olabilir, çünkü bu tür sistemlerde iki veya daha fazla iş parçacığı / işlem istendiğinde bir yarış durumu oluşabilir. bir semafor elde etmek için.

Evet, bellek mimariniz bir bellek bölümünün diğer tüm erişimleri geciktiren bir çekirdek / işlemci tarafından kilitlenmesini sağlıyorsa ve işlemcileriniz bir test ve set sunuyorsa, döndürme kilidi olmadan bir semafor uygulayabilirsiniz (ama çok dikkatli! ).

Bununla birlikte, basit / ucuz çok çekirdekli sistemler tasarlandığı için (gömülü sistemlerde çalışıyorum), tüm bellek mimarileri bu tür çok çekirdekli / çok işlemcili özellikleri desteklemez, yalnızca test edin ve ayarlayın veya eşdeğeri. Daha sonra bir uygulama aşağıdaki gibi olabilir:

  • döndürme kilidini edin (meşgul bekleme)
  • semafor edinmeye çalış
  • döndürme kilidini serbest bırakın
  • semafor başarıyla alınmadıysa, semafor serbest bırakılıncaya kadar geçerli iş parçacığını askıya alın; aksi takdirde kritik bölümle devam edin

Semaforun serbest bırakılması aşağıdaki gibi uygulanmalıdır:

  • döndürme kilidini edinmek
  • semaforu serbest bırakmak
  • döndürme kilidini serbest bırakın

Evet, ve işletim sistemi düzeyinde basit ikili semaforlar için, yedek olarak yalnızca bir döndürme kilidi kullanmak mümkün olacaktır. Ancak sadece korunacak kod bölümleri gerçekten çok küçükse.

Daha önce de belirtildiği gibi, kendi işletim sisteminizi uygularsanız ve uyguladığınızda dikkatli olun. Bu tür hataların hatalarını ayıklamak eğlencelidir (benim görüşüme göre pek çok kişi tarafından paylaşılmamaktadır), ancak çoğunlukla çok sıkıcı ve zordur.


1

Bir "muteks" (veya "karşılıklı dışlama kilidi"), iki veya daha fazla eşzamansız işlemin, özel kullanım için paylaşılan bir kaynağı ayırmak için kullanabileceği bir sinyaldir. "Muteks" in sahipliğini elde eden ilk süreç aynı zamanda paylaşılan kaynağın sahipliğini de elde eder. Diğer süreçler, elde etmeye çalışmadan önce ilk işlemin "muteks" sahipliğini serbest bırakmasını beklemelidir.

Çekirdekteki en yaygın kilitleme ilkeli spinlock'tur. Spinlock, çok basit tek tutuculu bir kilittir. Bir süreç bir spinlock almaya çalışırsa ve bu mevcut değilse, süreç kilidi elde edene kadar denemeye (dönmeye) devam edecektir. Bu sadelik, küçük ve hızlı bir kilit oluşturur.


1

Spinlock, ancak ve ancak, beklenen sonucunuzun çok kısa bir süre içinde, iş parçacığınızın yürütme dilim süresi sona ermeden önce gerçekleşeceğinden oldukça eminseniz kullanılır.

Örnek: Aygıt sürücüsü modülünde, sürücü donanım Register R0'da "0" yazar ve şimdi bu R0 yazmacının 1 olmasını beklemesi gerekir. H / W R0'ı okur ve bazı işler yapar ve R0'a "1" yazar. Bu genellikle hızlıdır (mikro saniye cinsinden). Şimdi dönme, uyumaktan çok daha iyidir ve H / W tarafından kesintiye uğratılır. Tabii ki, eğirme sırasında, H / W arıza durumuna dikkat edilmesi gerekiyor!

Bir kullanıcı uygulamasının dönmesi için kesinlikle hiçbir neden yoktur. Mantıklı değil. Bir olayın gerçekleşmesi için döneceksiniz ve bu olayın, hızlı zaman çerçevesi içinde gerçekleşmesi asla garanti edilmeyen başka bir kullanıcı seviyesi uygulama tarafından tamamlanması gerekiyor. Yani, kullanıcı modunda hiç dönmeyeceğim. Kullanıcı modunda uyumak () veya mutexlock () veya semafor kilidi () daha iyi.


1

Gönderen Ne Döndürme kilitler ve semaphorelar arasındaki fark nedir? Maciej Piechotka tarafından :

Her ikisi de sınırlı bir kaynağı yönetir. İlk önce ikili semafor (muteks) ve döndürme kilidi arasındaki farkı tanımlayacağım.

Döndürme kilitleri meşgul bir bekleme gerçekleştirir - yani döngüde çalışmaya devam eder:

while (try_acquire_resource ()); 
 ...  
serbest bırakmak();

Çok hafif bir kilitleme / kilit açma işlemi gerçekleştirir, ancak eğer kilitleme iş parçacığı aynı kaynağa erişmeye çalışan başkası tarafından önlenecekse, ikincisi basitçe CPU miktarı bitene kadar kaynağı elde etmeye çalışacaktır.
Öte yandan muteks daha çok şöyle davranır:

eğer (! try_lock ()) {
    add_to_waiting_queue ();
    Bekle();
}
...
süreç * p = get_next_process_from_waiting_queue ();
p-> uyanma ();

Dolayısıyla, iş parçacığı engellenen kaynağı almaya çalışırsa, bunun için uygun olana kadar askıya alınacaktır. Kilitleme / kilit açma çok daha ağır ancak bekleme "ücretsiz" ve "adil".

Semafor , birden çok kez (başlatmadan bilinir) kullanılmasına izin verilen bir kilittir - örneğin, 3 iş parçacığının aynı anda kaynağı tutmasına izin verilir, ancak daha fazla olamaz. Örneğin üretici / tüketici probleminde veya genel olarak kuyruklarda kullanılır:

P (resources_sem)
resource = kaynaklar.pop ()
...
resources.push (kaynaklar)
V (resources_sem)

Semafor, muteks ve spinlock arasındaki fark nedir?

Linux'ta Kilitleme


1
Bunun bir kopyası / yapıştırması gibi görünüyor ;-): Döndürme kilitleri ile semaforlar arasındaki fark nedir?
Hibou57

0

döndürme kilidi yalnızca bir işlem tarafından tutulabilirken, semafor bir veya daha fazla işlem tarafından tutulabilir. Döndürme kilidi, işlem bir kilidi serbest bırakana ve ardından bir kilit alana kadar bekleyin. Semafor uyku kilidi yani bekler ve uykuya geçer.

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.