Her ikisinin de aynı işi yaptığını düşünüyorum, senkronizasyon için hangisini kullanacağınıza nasıl karar veriyorsunuz?
Her ikisinin de aynı işi yaptığını düşünüyorum, senkronizasyon için hangisini kullanacağınıza nasıl karar veriyorsunuz?
Yanıtlar:
Teori
Teoride, bir iş parçacığı bir muteksi kilitlemeye çalıştığında ve başarılı olmazsa, muteks zaten kilitli olduğundan, hemen başka bir iş parçacığının çalışmasına izin verecek şekilde uykuya geçecektir. Uyandırılıncaya kadar uyumaya devam edecek, bu da muteks kilidin daha önce kilitte tuttuğu her iplik tarafından açıldıktan sonra geçerli olacaktır. Bir iş parçacığı bir döndürme kilidini kilitlemeye çalıştığında ve başarılı olmadığında, sonunda başarılı olana kadar sürekli olarak yeniden kilitlemeyi dener; bu nedenle başka bir iş parçacığının yerini almasına izin vermez (bununla birlikte, mevcut iş parçacığının CPU çalışma zamanı kuantumu aşıldığında, işletim sistemi zorla başka bir iş parçacığına geçer).
Sorun
Mutekslerle ilgili sorun, ipliklerin uykuya alınması ve tekrar uyanmasının hem oldukça pahalı işlemler olması hem de oldukça fazla CPU talimatına ihtiyaç duymaları ve bu nedenle biraz zaman almalarıdır. Eğer muteks sadece çok kısa bir süre için kilitlenmişse, bir ipliğin uykuya alınması ve tekrar uyandırılması için harcanan zaman, ipliğin gerçekte uyuduğu süreyi aşabilir ve hatta ipliğin geçeceği süreyi aşabilir bir spinlock üzerinde sürekli yoklama yaparak israf var. Öte yandan, bir döndürme kilidindeki yoklama sürekli CPU zamanını boşa harcar ve kilit daha uzun bir süre tutulursa, bu çok daha fazla CPU zamanı harcar ve bunun yerine iplik uyuyorsa çok daha iyi olurdu.
Çözüm
Tek çekirdekli / tek CPU sisteminde spinlock kullanmak genellikle bir anlam ifade etmez, çünkü spinlock yoklaması yalnızca mevcut CPU çekirdeğini bloke ettiği sürece başka hiçbir iş parçacığı çalışamaz ve başka hiçbir iş parçacığı çalışamayacağı için kilit çalışmaz kilidini açmak. IOW, bir spinlock, gerçek bir fayda sağlamak için bu sistemlerde yalnızca CPU süresini harcar. Eğer iplik uykuya daldıysa, başka bir iplik bir kerede koşmuş olabilir, muhtemelen kilidin kilidini açabilir ve sonra tekrar uyandıktan sonra ilk ipliğin işlemeye devam etmesine izin verebilirdi.
Çok çekirdekli / çok işlemcili sistemlerde, yalnızca çok kısa bir süre için tutulan çok sayıda kilit bulunan, sürekli iş parçacığı uyku moduna geçirmek ve tekrar uyanmak için harcanan zaman, çalışma zamanı performansını önemli ölçüde düşürebilir. Bunun yerine spinlock'ları kullanırken, iş parçacıkları tam çalışma zamanı kuantumlarından yararlanma şansına sahip olurlar (her zaman sadece çok kısa bir süre için engellerler, ancak daha sonra çalışmalarına hemen devam ederler), bu da çok daha yüksek işlem hacmine yol açar.
Pratik
Programcılar sıklıkla mutekslerin veya spinlock'ların daha iyi olup olmayacağını önceden bilemediğinden (örn. Hedef mimarinin CPU çekirdeği sayısı bilinmediğinden) veya işletim sistemleri belirli bir kod parçasının tek çekirdekli veya çok çekirdekli ortamlarda, çoğu sistem muteksler ve spinlock'lar arasında kesin bir ayrım yapmaz. Aslında, çoğu modern işletim sistemi hibrid mutekslere ve hibrit spinloklara sahiptir. Bu aslında ne anlama geliyor?
Hibrit bir muteks, ilk başta çok çekirdekli bir sistemde spinlock gibi davranır. Bir iş parçacığı muteksi kilitleyemezse, muteks yakında açılabileceğinden hemen uykuya konulmaz, bu nedenle muteks önce tam olarak bir spinlock gibi davranacaktır. Sadece belirli bir süre sonra kilit elde edilmemişse (veya tekrar dener veya başka bir ölçüm faktörü), iplik gerçekten uyku moduna geçirilir. Aynı kod sadece tek çekirdekli bir sistemde çalışıyorsa, muteks dönmez, ancak yukarıda görüldüğü gibi, bu yararlı olmaz.
Bir hibrit spinlock ilk başta normal bir spinlock gibi davranır, ancak çok fazla CPU zamanını boşa harcamamak için bir geri çekilme stratejisi olabilir. Genellikle ipliği uykuya geçirmez (çünkü bir spinlock kullanırken olmasını istemezsiniz), ancak ipliği durdurmaya (hemen veya belirli bir süre sonra) karar verebilir ve başka bir iş parçacığının çalışmasına izin verebilir Böylece, spinlock kilidinin açılması şansı artar (saf bir iplik anahtarı genellikle bir ipliği uykuya sokmayı ve daha sonra tekrar olmasa da daha sonra tekrar uyandırmayı içeren bir düğmeden daha ucuzdur).
özet
Şüphe duyuyorsanız, muteksleri kullanın, genellikle daha iyi bir seçimdir ve çoğu modern sistem, yararlı görünüyorsa, çok kısa bir süre için dönmelerine izin verecektir. Spinlock'ları kullanmak bazen performansı artırabilir, ancak yalnızca belirli koşullar altında ve şüphe duyduğunuzda bana bir spinlock'un faydalı olabileceği herhangi bir proje üzerinde çalışmadığınızı söyler. Dahili olarak bir spinlock veya mutex kullanabilen kendi "kilit nesnesini" kullanmayı düşünebilirsiniz (örneğin, bu davranış böyle bir nesne oluştururken yapılandırılabilir), başlangıçta her yerde muteksler kullanın ve bir yerde spinlock kullanmanın gerçekten olabileceğini düşünüyorsanız yardım edin, deneyin ve sonuçları karşılaştırın (örneğin bir profil oluşturucu), ancak her iki durumu da test ettiğinizden emin olun,
Aslında iOS'a özgü değil, ancak iOS çoğu geliştiricinin bu sorunla karşılaşabileceği bir platformdur: Sisteminizde bir iplik zamanlayıcı varsa, önceliği ne kadar düşük olursa olsun, herhangi bir iş parçacığının sonunda çalışma şansı elde edeceğini garanti etmez, spinloklar kalıcı kilitlenmelere yol açabilir. İOS zamanlayıcı, daha düşük bir sınıftaki farklı iş parçacığı sınıflarını ve iş parçacıklarını yalnızca daha yüksek bir sınıftaki hiçbir iş parçacığı da çalışmak istemiyorsa çalışır. Bunun için bir back-off stratejisi yoktur, bu nedenle kalıcı olarak yüksek sınıf iş parçacıkları varsa, düşük sınıf iş parçacıkları hiçbir zaman CPU zamanı elde etmez ve bu nedenle hiçbir zaman herhangi bir iş yapma şansı yoktur.
Sorun aşağıdaki gibi görünür: Kodunuz, düşük prio sınıfı bir iş parçacığında bir spinlock alır ve bu kilidin ortasında, zaman kuantum aşıldı ve iş parçacığı çalışmayı durdurur. Bu spinlock'un tekrar serbest bırakılmasının tek yolu, düşük prio sınıfı iş parçacığının tekrar CPU zamanı alması ancak bunun garanti edilmemesi. Sürekli olarak çalıştırmak isteyen birkaç yüksek prio sınıfı iş parçacığına sahip olabilirsiniz ve görev zamanlayıcısı her zaman bunlara öncelik verir. Bunlardan biri dönüş kilidinin üzerinden geçebilir ve elde etmeye çalışabilir, ki bu elbette mümkün değildir ve sistem verimi sağlayacaktır. Sorun şudur: Geri dönen bir iplik hemen tekrar çalışmaya hazırdır! Kilidi tutan iplikten daha yüksek bir prioya sahip olan kilidi tutan iplik CPU çalışma zamanını elde etme şansı yoktur.
Mutekslerde bu sorun neden oluşmuyor? Yüksek prio iplik muteksi elde edemediğinde verim vermez, biraz dönebilir ancak sonunda uykuya gönderilir. Uyku olayı bir olay tarafından uyandırılıncaya kadar çalıştırılamaz, örneğin, bekleyen muteks kilidi gibi bir olay. Apple bu sorunun farkındadır ve OSSpinLock
sonuç olarak kullanımdan kaldırılmıştır . Yeni kilit çağrılır os_unfair_lock
. Bu kilit, farklı iplik önceliği sınıflarının farkında olduğu için yukarıda belirtilen durumdan kaçınır. İOS projenizde spinlock kullanmanın iyi bir fikir olduğundan eminseniz, bunu kullanın. Uzak durOSSpinLock
! Ve hiçbir koşulda iOS'ta kendi spinlock'larınızı uygulamayın! Şüpheniz varsa, bir muteks kullanın! macOS, CPU zamanında herhangi bir iş parçacığının (düşük prio iş parçacıkları bile) "kuru çalışmasına" izin vermeyen farklı bir iş parçacığı zamanlayıcısına sahip olduğundan bu sorundan etkilenmez, yine de aynı durum orada ortaya çıkabilir ve daha sonra çok zayıf dolayısıyla OSSpinLock
macOS'ta da kullanımdan kaldırılmıştır.
Mecki'nin önerisiyle devam eden bu makale , Alexander Sandler'in blogunda mutex vs pthread spinlock adlı Linux makalesinde Alex, #ifdef kullanarak davranışı test etmek için nasıl spinlock
& nasıl uygulanabileceğini gösteriyor mutexes
.
Bununla birlikte, gözleminize göre son çağrıyı aldığınızdan emin olun, verilen örnek izole bir durum, proje gereksiniminiz, ortamınız tamamen farklı olabilir.
Ayrıca, belirli ortamlarda ve koşullarda (dağıtım düzeyindeki pencerelerde çalıştırma = = DISPATCH LEVEL gibi) mutex'i değil, spinlock'u kullanabileceğinizi unutmayın. Unix'te - aynı şey.
İşte rakip stackexchange unix sitesinde eşdeğer bir soru: /unix/5107/why-are-spin-locks-good-choices-in-linux-kernel-design-instead-of-something- Daha
Windows sistemlerinde gönderim hakkında bilgi: http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/IRQL_thread.doc
Mecki'nin cevabı oldukça iyi çiviler. Ancak, tek bir işlemcide, görev bir Kesinti Hizmeti yordamı tarafından verilmek üzere kilidi beklerken döndürme kilidi kullanmak anlamlı olabilir. Kesinti, kontrolü ISR'ye aktarır ve bu da kaynağı bekleyen görev tarafından kullanıma hazır hale getirir. Kesilen göreve kontrolü vermeden önce kilidi serbest bırakarak sona erer. Eğirme görevi, eğirme kilidini bulabilir ve devam eder.
Spinlock ve Mutex senkronizasyon mekanizmaları günümüzde oldukça yaygındır.
Önce Spinlock'u düşünelim.
Temelde meşgul bir bekleme eylemidir, yani bir sonraki eyleme geçmeden önce belirli bir kilidin serbest bırakılmasını beklememiz gerekir. Kavramsal olarak çok basit, uygularken durum böyle değil. Örneğin: Kilit serbest bırakılmadıysa, iplik takas edildi ve uyku durumuna geçti, bununla ilgilenmeli miyiz? İki iş parçacığı aynı anda erişim istediğinde senkronizasyon kilitleriyle nasıl başa çıkılır?
Genel olarak, en sezgisel fikir, kritik bölümü korumak için bir değişken üzerinden senkronizasyon ile uğraşmaktır. Mutex kavramı benzer, ancak yine de farklı. Odaklan: CPU kullanımı. Spinlock, eylemi beklemek için CPU zamanını tüketir ve bu nedenle, ikisi arasındaki farkı özetleyebiliriz:
Homojen çok çekirdekli ortamlarda, kritik bölümdeki zaman harcaması Spinlock kullanmaktan daha azsa, bağlam değiştirme süresini azaltabiliriz. (Tek çekirdekli karşılaştırma önemli değildir, çünkü bazı sistemlerin anahtarın ortasında Spinlock uygulaması)
Windows'ta, Spinlock kullanımı iş parçacığını DISPATCH_LEVEL'e yükseltir, bu da bazı durumlarda izin verilmeyebilir, bu nedenle bu sefer Mutex (APC_LEVEL) kullanmamız gerekti.
Tek çekirdekli / tek CPU sisteminde spinlocks kullanmak genellikle bir anlam ifade etmez, çünkü spinlock yoklaması yalnızca mevcut CPU çekirdeğini bloke ettiği sürece başka hiçbir iş parçacığı çalışamaz ve başka hiçbir iş parçacığı çalışamayacağı için kilit çalışmaz kilidini açmak. IOW, bir spinlock, gerçek bir fayda sağlamak için bu sistemlerde yalnızca CPU zamanını harcar
Bu yanlış. Uni işlemci sistemlerinde spinlock'ları kullanmada cpu döngüleri israfı yoktur, çünkü bir işlem bir spin kilidi aldığında, önleme devre dışı bırakılır, bu nedenle, başka kimse dönemez! Sadece onu kullanmanın bir anlamı yok! Bu nedenle, Uni sistemlerindeki spinloklar derleme zamanında çekirdek tarafından preempt_disable ile değiştirilir!