volatile
Anahtar kelime hakkında bazı makaleler okudum ama doğru kullanımını bulamadım. C # ve Java'da ne için kullanılması gerektiğini bana söyler misiniz?
volatile
Anahtar kelime hakkında bazı makaleler okudum ama doğru kullanımını bulamadım. C # ve Java'da ne için kullanılması gerektiğini bana söyler misiniz?
Yanıtlar:
Hem C # hem de Java için "uçucu", derleyiciye bir değişkenin değerinin programın kendi kapsamı dışında değişebileceği için hiçbir zaman önbelleğe alınmaması gerektiğini söyler. Derleyici, değişken "kontrolünün dışında" değişirse sorunlara neden olabilecek optimizasyonlardan kaçınacaktır.
Şu örneği düşünün:
int i = 5;
System.out.println(i);
Derleyici, aşağıdaki gibi 5'i yazdırmak için bunu optimize edebilir:
System.out.println(5);
Ancak, değişebilecek başka bir iş parçacığı varsa i
, bu yanlış davranıştır. Başka bir iş parçacığı i
6 olarak değişirse , optimize edilmiş sürüm yine de 5 yazdıracaktır.
volatile
Anahtar bu optimizasyonu ve önbelleğe alma önler ve böylece değişken bir iş parçacığı tarafından değiştirilebilir yararlıdır.
i
olarak işaretlenerek hala geçerli olacağına inanıyorum volatile
. Java'da her şey önceden olan ilişkilerle ilgilidir.
i
yerel bir değişkendir, başka hiçbir iş parçacığı yine de değiştirebilir. Bir alansa, derleyici, olmadığı sürece aramayı optimize edemez final
. Derleyicinin, bir alanın final
açıkça bildirilmediğinde "göründüğünü" varsayarak optimizasyonlar yapabileceğini sanmıyorum .
Uçucunun bir değişkene ne yaptığını anlamak için, değişken uçucu olmadığında ne olduğunu anlamak önemlidir.
İki evre A ve B geçici olmayan bir değişkene erişirken, her evre değişkenin yerel bir kopyasını yerel önbelleğinde tutacaktır. A iş parçacığı tarafından yerel önbelleğinde yapılan herhangi bir değişiklik, iş parçacığı B tarafından görünmez.
Değişkenler uçucu olarak bildirildiğinde, bu, esasen, iş parçacıklarının böyle bir değişkeni önbelleğe almaması gerektiği veya başka bir deyişle, evrelerin, doğrudan ana bellekten okunmadıkça bu değişkenlerin değerlerine güvenmemesi gerektiği anlamına gelir.
Peki, bir değişken ne zaman uçucu hale getirilir?
Birçok iş parçacığı tarafından erişilebilen bir değişkene sahip olduğunuzda ve her iş parçacığının, değer başka bir iş parçacığı / işlem / programın dışında güncellense bile, o değişkenin en son güncellenmiş değerini almasını istiyorsanız.
Uçucu alanların okumaları anlam kazanır . Bu, uçucu değişkenden okunan belleğin sonraki bellek okumalarından önce gerçekleşeceğinin garanti edildiği anlamına gelir. Derleyicinin yeniden sıralamayı yapmasını engeller ve eğer donanım gerektiriyorsa (zayıf sıralı CPU), donanımın uçucu okumadan sonra gerçekleşen ancak spekülatif olarak erken başlatılan tüm okumaları temizlemesi için özel bir talimat kullanacaktır, aksi takdirde CPU olabilir Yük alma sorunu ile emekliye ayrılma arasında herhangi bir spekülatif yük oluşmasını önleyerek, ilk etapta erken yayınlanmasını önlemek.
Uçucu alanların yazıları serbest bırakma anlamlarına sahiptir . Bu, uçucu değişkene herhangi bir bellek yazma işleminin, önceki tüm bellek yazma işlemlerinin diğer işlemciler tarafından görülebilene kadar geciktirilmesinin garanti edildiği anlamına gelir.
Aşağıdaki örneği düşünün:
something.foo = new Thing();
foo
Bir sınıftaki üye değişkendiyse ve diğer CPU'lar tarafından atıfta bulunulan nesne örneğine erişime sahipse , yapıcıdaki bellek yazmaları genel olarak görünür olmadan öncesomething
değer foo
değişikliğini görebilirler! "Zayıf sıralı bellek" bu demektir. Bu, derleyicinin yapıcıdaki tüm depolara depodan önce sahip olsa bile oluşabilir . Eğer bir o kadar mağaza açma anlambilim sahip olacak ve donanım garanti yazma öncesi yazıyor bütün bunlara yazma izin vermeden önce diğer işlemciler tarafından görülebilir oluşmaya.Thing
foo
foo
volatile
foo
foo
foo
foo
Yazıların bu kadar kötü bir şekilde yeniden sıralanması nasıl mümkün olabilir? Önbellek satırı tutma foo
yeri önbellekteyse ve yapıcıdaki mağazalar önbelleği kaçırdıysa, mağazanın önbelleğe yazılanlardan çok daha erken tamamlanması mümkündür.
Intel'in (berbat) Itanium mimarisi hafızayı zayıf bir şekilde sipariş etmişti. Orijinal XBox 360'ta kullanılan işlemcinin belleği yetersizdi. Çok popüler ARMv7-A dahil olmak üzere birçok ARM işlemcisi, hafızayı zayıf bir şekilde sipariş etti.
Geliştiriciler genellikle bu veri yarışlarını görmezler çünkü kilitler gibi şeyler tam bir bellek bariyeri yapar, esasen aynı anda anlambilim edinme ve yayınlama ile aynı şeydir. Kilidin içindeki hiçbir yük, kilit alınmadan önce spekülatif olarak yürütülemez, kilit alınana kadar ertelenir. Bir kilit serbest bırakma sürecinde hiçbir mağaza geciktirilemez, kilidi serbest bırakan talimat, kilit içinde yapılan tüm yazmalar genel olarak görünür olana kadar ertelenir.
Daha eksiksiz bir örnek "Çift kontrol edilmiş kilitleme" modelidir. Bu modelin amacı, bir nesneyi tembel olarak başlatmak için her zaman bir kilit elde etmek zorunda kalmamaktır.
Wikipedia'dan alıntı:
public class MySingleton {
private static object myLock = new object();
private static volatile MySingleton mySingleton = null;
private MySingleton() {
}
public static MySingleton GetInstance() {
if (mySingleton == null) { // 1st check
lock (myLock) {
if (mySingleton == null) { // 2nd (double) check
mySingleton = new MySingleton();
// Write-release semantics are implicitly handled by marking
// mySingleton with 'volatile', which inserts the necessary memory
// barriers between the constructor call and the write to mySingleton.
// The barriers created by the lock are not sufficient because
// the object is made visible before the lock is released.
}
}
}
// The barriers created by the lock are not sufficient because not all threads
// will acquire the lock. A fence for read-acquire semantics is needed between
// the test of mySingleton (above) and the use of its contents. This fence
// is automatically inserted because mySingleton is marked as 'volatile'.
return mySingleton;
}
}
Bu örnekte, MySingleton
yapıcıdaki depolar , depodan önce diğer işlemciler tarafından görülmeyebilir mySingleton
. Böyle bir durumda, mySingleton'a göz atan diğer iş parçacıkları bir kilit elde etmeyecek ve yazımları kurucuya almaları gerekmeyecektir.
volatile
asla önbelleğe almayı engellemez. Yaptığı şey, diğer işlemcilerin yazma "gördükleri" sırayı garantilemektir. Bir mağaza sürümü, bekleyen tüm yazmalar tamamlanana ve diğer işlemcilere, ilgili satırları önbelleğe almışlarsa önbellek satırlarını atmalarını / geri yazmalarını söyleyen bir veri yolu döngüsü verilinceye kadar bir mağazayı erteleyecektir. Yük alımı, tahmin edilen tüm okumaları temizleyerek bunların geçmişten eski değerler olmamasını sağlar.
head
ve tail
ihtiyaç varsayarak gelen yapımcı önlemek için uçucu olması tail
olmaz değişikliği ve varsayarak tüketiciyi önlemek için head
değişiklik olmaz. Ayrıca, head
kuyruğa yazılan verilerin deponun head
genel olarak görünür hale gelmesinden önce global olarak görünür olmasını sağlamak için geçici olmalıdır .
Uçucu anahtar kelime hem Java ve C # farklı anlamlara gelir.
Gönderen Java Dil Spec :
Bir alan geçici olarak tanımlanabilir, bu durumda Java bellek modeli tüm iş parçacıklarının değişken için tutarlı bir değer görmesini sağlar.
Uçucu anahtar kelimedeki C # Referansından :
Volatile anahtar sözcüğü, programdaki bir alanın işletim sistemi, donanım veya eşzamanlı olarak yürütülen bir iş parçacığı gibi bir şey tarafından değiştirilebileceğini belirtir.
Java'da, JVM'ye değişkenin aynı anda birden çok iş parçacığı tarafından kullanılabileceğini söylemek için "uçucu" kullanılır, bu nedenle belirli ortak optimizasyonlar uygulanamaz.
Özellikle aynı değişkene erişen iki iş parçacığının aynı makinedeki ayrı CPU'larda çalıştığı durum. CPU'ların tuttuğu verileri agresif bir şekilde önbelleğe alması çok yaygındır çünkü bellek erişimi önbellek erişiminden çok daha yavaştır. Bu, veri CPU1'de güncellenirse , önbellek kendini temizlemeye karar verdiğinde bunun yerine hemen tüm önbelleklerden ve ana belleğe geçmesi gerektiği anlamına gelir , böylece CPU2 güncellenmiş değeri görebilir (yine yoldaki tüm önbellekleri göz ardı ederek).
Uçucu olmayan verileri okurken, çalıştırılan iş parçacığı her zaman güncellenmiş değeri alabilir veya almayabilir. Ancak nesne uçucuysa, iş parçacığı her zaman en güncel değeri alır.
Volatile, eşzamanlılık sorununu çözmektir. Bu değeri senkronize yapmak için. Bu anahtar kelime çoğunlukla bir threading içinde kullanılır. Birden çok iş parçacığı aynı değişkeni güncellediğinde.