|
|
Yayınlandı 27.08.2018 14:40:35
|
|
|

Diyelim ki birden fazla iş parçacığı tarafından erişilebilen halka açık bir int sayacı alanı içeren bir sınıf var ve bu sayı sadece artar veya azalır.
Bu alan eklenirken, aşağıdaki şemalardan hangisi kullanılmalıdır ve neden?
- kilit(this.locker) this.counter++;
- Kilitli.Artış (b. this.counter);
- Sayaç erişim değiştiricisini public volatile olarak değiştirin
En kötüsü (hiçbiri gerçekten işe yaramıyor)
Sayaç erişim değiştiricisini public volatile olarak değiştirin
Bu yaklaşım aslında hiç güvenli değildir ve değişkenlikle ilgili önemli nokta, birden fazla CPU üzerinde çalışan birden fazla iş parçacığının verileri tamponlaması ve çalıştırılan komutları yeniden düzenlemesidir.
Eğer değişken değilse, CPU A bir değer arttığında, CPU B artan değeri görmek için biraz beklemelidir, bu da sorunlara yol açabilir.
Eğer değişkense, her iki CPU'nun aynı anda aynı değeri görmesini sağlar. Ama çapraz okuma ve yazma işlemlerinden kaçınmıyor.
Bir değişkene değer eklemek aslında üç adım gerektirir
1. Okuma, 2. 3. Yaz
Diyelim ki iş parçacığı A sayacın değerini 1 olarak okuyor ve artmaya hazır değil, sonra iş parçacığı B de sayaç değerini 1 olarak okur ve her iki iş parçacığı da artım ve yazma işlemleri yapmaya başlar. Son sayaçın değeri 2'dir. Bu doğru değil, her iki iş parçacığı da bir artırma işlemi yaptı ve doğru sonuç 3 olmalı. Bu yüzden değişken olarak etiketlemek tamamen güvenli değildir.
Daha iyi
kilit(this.locker) this.counter++;
Bu şekilde güvenli olur (tabii ki bu sayaca erişmek istediğiniz her yeri kilitlemeyi unutmayın). Bu, kilitli kodu başka herhangi bir iş parçacığı çalıştırmasını engeller. Ayrıca yukarıda bahsedilen çoklu CPU komut dizileme sorununu da önler. Sorun şu ki, kilit performansında yavaş ve başka alakasız yerlerde kilitleme kullanırsanız diğer iş parçacıklarını engelleyebilir.
En iyisi
Kilitli.Artış (b. this.counter);
Bu güvenli ve çok verimli. Bir atomda ortada kesinti olmadan üç okuma, artırma ve yazma işlemlerini gerçekleştirir. Çünkü diğer kodları etkilemiyor, başka yerlerde kilitleri hatırlamanıza gerek yok. Ayrıca çok hızlı (MSDN'nin dediği gibi, günümüz CPU'larında genellikle sadece bir komut oluyor).
Ama CPU'nun komut sıralaması sorununu da çözüp çözemeyeceğinden tam emin değilim, yoksa volatile ve bu artışla birlikte mi kullanılması gerekiyor.
Ek: Volatile hangi sorunları iyi çözer?
Volatile çoklu iş parçacığı engelleyemediği için ne yapabilir? İyi bir örnek olarak, iki iş parçacığına sahip olmanız olur; biri her zaman bir değişkene yazar, diyelim ki bu değişken queneLength, diğeri ise her zaman bu değişkenden veri okur. QueueLenght değişken değilse, iş parçacığı A 5 kez okunabilir, ancak iş parçacığı B gecikmiş veri görebilir veya hatta veri yanlış sırayla olabilir. Bir çözüm lock kullanmaktır, ama bu durumda volatile de kullanılabilir. Bu, iş parçacığı B'nin her zaman iş parçacığı A tarafından yazılmış en son verileri görmesini sağlar, ancak bu mantık yalnızca yazarken okumazsanız ve okurken yazmazsanız çalışır. Birden fazla iş parçacığı okuma-değiştirme-yazma işlemleri yapmak istediğinde, Interlocked veya lock kullanmanız gerekir.
|
Önceki:Java MD5 şifreleme yöntemiÖnümüzdeki:Linq, SQL'de koşullu sorguları not in ve in uygular
|