Kilitleme durumunda yarış koşullarını ne önler?


24

Veri yarışlarının ne olduğunun temellerini ve kilitlerin / mutekslerin / semaforların bunların önlenmesine nasıl yardımcı olduğunu biliyorum. Ama kilidin kendisinde bir "yarış durumu" varsa ne olur? Örneğin, belki aynı uygulamada, ancak farklı işlemciler üzerinde çalışan iki farklı iş parçacığı, aynı anda bir kilit almaya çalışın .

O zaman ne olacak? Bunu önlemek için ne yapılır? İmkansız mı, yoksa sadece ihtimal dışı mı? Yoksa gerçekleşmesini bekleyen gerçek bir yarış durumu mu?


Bu soru daha önce SO'da sorulmuştu: stackoverflow.com/questions/980521/…
Doc Brown

ve ilgili bir soru burada P.SE'de: programmers.stackexchange.com/questions/228827/…
cırcır

Kilidi almak için bir kilit elde edersiniz;) (Başka bir deyişle, kilidinizin bir yarış koşulu varsa, doğru şekilde uygulanmaz - bir kilit, karşılıklı dışlamayı uygulayan bir yapı olarak tanımlanır)
Tangs

Sen önemli bir noktadan cevapsız nasıl kilitler çalışması. Kilitlenerek yarış yapmak mümkün olmayacak şekilde inşa edilirler, aksi takdirde tamamen yararsızdırlar.
Zane

Yanıtlar:


36

İmkansız mı, yoksa sadece ihtimal dışı mı?

İmkansız. Farklı şekillerde uygulanabilir, örneğin, donanımın sıralı yürütmeyi garanti ettiği Karşılaştırma ve Değiştirme yoluyla . Çok sayıda çekirdek veya hatta çok sayıda soketin varlığında biraz karmaşık olabilir ve çekirdekler arasında karmaşık bir protokole ihtiyaç duyar , ancak bunların hepsi halledilir.


3
Tanrıya şükür ... Tanrım ... donanımda işleniyor ... (ya da en azından dokunduğumuzdan daha düşük bir seviyede.)
corsiKa

2
@gdhoward Buna inanamıyorum ... bu cevap 5 dakikadan daha az sürdü ve dördüncü yüz cevaplarımdan en çok oy alan üçüncü oydu (çoğunlukla SO). Ve ayrıca muhtemelen en kısa olanı.
maaartinus

1
@ Maaartinus - Kısa ve tatlı bazen yapar.
Bobson,

17

Atomik "Test ve Küme" işlemleri kavramını incelemek.

Esasen operasyon bölünemez - iki şeyin aynı anda yapılması mümkün değildir. Bir değeri kontrol edecek, açıksa ayarlayacak ve değeri test sırasında olduğu gibi döndürecektir. Bir kilitleme işleminde, sonuç bir test ve ayarlamanın ardından her zaman "kilit == DOĞRU" olacaktır, tek fark başlangıçta ayarlanmış ya da olmamaktır.

Tek çekirdekli bir işlemcideki mikro kod düzeyinde, bu bölünmez bir talimattır ve uygulanması kolaydır. Çok çekirdekli ve çok çekirdekli işlemcilerle zorlaşıyor, ancak programcılar olarak, silikonu gerçekten zeki adamlar tarafından çalışmak üzere tasarlandığından endişelenmeye gerek yok. Temel olarak aynı şeyi yapıyorlar - test-ve-set'in fantezi versiyonunun atomik bir talimatı var


2
Temel olarak, eğer donanım belirli bir seviyede kendinden sekanslı değilse, aksi takdirde oluşabilecek bağları kırmasına izin veren bir mekanizmaya sahip olacaktır.
Bill Michell

@ BillMichell, bunu düşünmeliydim. Aslında yaptım; Varsayımımın doğru olup olmadığını bilmiyordum.
Gavin Howard

2

Basitçe kritik bölüme girmek için kodu koymak özel olarak tasarlanmıştır, böylece bir yarış durumu karşılıklı dışlamayı ihlal etmez.

Atomik karşılaştırma ve ayarlama döngülerinin çoğu, donanım seviyesinde yürütülen zaman kullanılır

while(!CompareAndSet(&lock, false, true));//busy loop won't continue until THIS thread has set the lock to true
//critical section
CompareAndSet(&lock, true, false);

Bunun yokluğunda, karşılıklı dışlamayı sağlamak için iyi çalışılmış yazılım çözümleri vardır .


1

İki (veya daha fazla) ipliğin aynı anda kilitlenmesi mümkün değildir. Örneğin, birkaç tür senkronizasyon yöntemi vardır:

Aktif bekleme - sıkma kilidi

pseudocode:

1. while ( xchg(lock, 1) == 1); - entry protocole

XCHG, önce bir "kilit" değişkeni için yeni bir değer ayarlayan ve daha sonra eski değeri döndüren bir atomik işlem örneğidir (x86 mimarisinde var). Atomik, kesilemeyeceği anlamına gelir - yukarıdaki örnekte yeni değer ayarlama ve eskiye dönüş arasında. Atomik - deterministik sonuç ne olursa olsun.

2. Your code
3. lock = 0; - exit protocol

Kilit 0'a eşit olduğunda, kritik bölüme başka bir diş girebilir - döngü biter.

İplik askıya alma - örneğin semafor sayımı

İki atomik işlem var .Wait()ve .Signal()tamsayı değişkenimiz onu çağırmamıza izin veriyor int currentValue.

Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;

Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;

Şimdi kritik bölüm problemini çözmek gerçekten kolay:

pseudocode:

mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();

Genellikle programlama iş parçacığı API'niz semafor kritik bölümünde en fazla eşzamanlı iş parçacığı belirtebilmenizi sağlar. Açıkçası, çok iş parçacıklı sistemlerde (mutex, monitörler, ikili semafor vb.) Daha fazla senkronizasyon türü var, ancak yukarıdaki fikirlere dayanıyorlar. İplik askıya alma yöntemlerinin aktif beklemede tercih edilmesi gerektiği söylenebilir (böylece cpu israf edilmez) - bu her zaman gerçek değildir. İplik askıya alındığında - bağlam anahtarı adı verilen pahalı işlem gerçekleşir. Ancak, bekleme süresi kısa olduğunda (diş sayısı ~ çekirdek sayısı) makul olur.

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.