uçucu (bilgisayar programlama) - volatile (computer programming)


Gelen bilgisayar programlama özellikle de, C , C ++ , C # ve Java programlama dilleri , uçucu anahtar bir işaret değeri o değiştirilmiş görünüyor olmasa bile, farklı erişimler arasında değişebilir. Bu anahtar sözcük, en iyi duruma getiren bir derleyicinin sonraki okumaları veya yazmaları en iyi duruma getirmesini ve dolayısıyla eski bir değeri hatalı bir şekilde yeniden kullanmasını veya yazma işlemlerini atlamasını engeller . Uçucu değerleri esas olarak donanım erişim (ortaya çıkan bellek eşlemeli I / O ile iletişim kurmak için kullanılan okuma veya belleğe yazma), çevresel aygıtlar , ve diş farklı iplik bir değer değiştirilmiş olabilir.

Ortak bir anahtar kelime olmasına rağmen, davranışı volatileprogramlama dilleri arasında önemli ölçüde farklılık gösterir ve kolayca yanlış anlaşılır. C ve C ++, eğer bu bir türü eleme gibi, constve bir özelliğidir türü . Ayrıca, C ve C ++ da yok değil en diş senaryolarda ve bu kullanılması önerilmez. Java ve C#'da, bir değişkenin özelliğidir ve değişkenin bağlı olduğu nesnenin mutasyona uğrayabileceğini ve özellikle iş parçacığı için tasarlandığını belirtir . In D programlama dili, orada ayrı bir anahtar kelimedir sharedparçacığı kullanımı için, ancak hiçbir volatileanahtar kelime var.

C ve C++'da

C'de ve dolayısıyla C++'da, volatileanahtar kelimenin amacı

  • bellek eşlemeli G/Ç cihazlarına erişime izin ver
  • setjmpve arasındaki değişkenlerin kullanımına izin verlongjmp
  • sig_atomic_tsinyal işleyicilerde değişkenlerin kullanımına izin verir .

Hem C hem de C++ tarafından amaçlanmış olsa da, C standartları, volatileanlambilimin başvurulan nesneye değil, değere atıfta bulunduğunu ifade etmekte başarısız olur . İlgili kusur raporu DR 476 (C11'e) C17 ile halen inceleme aşamasındadır.

volatileDeğişkenler üzerindeki işlemler atomik değildir ve iş parçacığı için uygun bir gerçekleşmeden önce ilişkisi kurmazlar. Bu, ilgili standartlarda (C, C++, POSIX , WIN32) belirtilmiştir ve geçici değişkenler, mevcut uygulamaların büyük çoğunluğunda iş parçacığı güvenli değildir. Bu nedenle, volatileanahtar kelimenin taşınabilir bir senkronizasyon mekanizması olarak kullanılması birçok C/C++ grubu tarafından önerilmez.

C'de bellek eşlemeli G/Ç örneği

Bu örnekte, kod saklanan değerini ayarlar fooiçin 0. Daha sonra, şu şekilde değişene kadar bu değeri art arda yoklamaya başlar 255:

static int foo;

void bar(void) {
    foo = 0;

    while (foo != 255)
         ;
}

Bir optimizasyon derleyicisi , içinde depolanan değeri başka hiçbir kodun değiştiremeyeceğini fark edecek ve her zaman fooeşit kalacağını varsayacaktır 0. Bu nedenle derleyici, fonksiyon gövdesini buna benzer bir sonsuz döngü ile değiştirecektir :

void bar_optimized(void) {
    foo = 0;

    while (true)
         ;
}

Ancak, CPU'ya bağlı bir aygıtın donanım kaydıfoo gibi, bilgisayar sisteminin diğer öğeleri tarafından herhangi bir zamanda değiştirilebilen bir konumu temsil edebilir . Yukarıdaki kod böyle bir değişikliği asla algılamaz; anahtar sözcüğü olmadan, derleyici geçerli programın değeri değiştirebilecek sistemin tek parçası olduğunu varsayar (ki bu açık ara en yaygın durumdur). volatile

Derleyicinin kodu yukarıdaki gibi optimize etmesini önlemek için volatileanahtar kelime kullanılır:

static volatile int foo;

void bar (void) {
    foo = 0;

    while (foo != 255)
        ;
}

Bu değişiklikle, döngü koşulu optimize edilmeyecek ve sistem, değişikliği meydana geldiğinde algılayacaktır.

Genel olarak platformlarda (C++11'de açığa çıkan) volatile yerine tercih edilmesi gereken bellek bariyeri işlemleri vardır, çünkü bunlar derleyicinin daha iyi optimizasyon yapmasına izin verir ve daha da önemlisi çok iş parçacıklı senaryolarda doğru davranışı garanti eder; ne C belirtimi (C11'den önce) ne de C++ belirtimi (C++11'den önce) çok iş parçacıklı bir bellek modeli belirtmez, bu nedenle geçici işletim sistemleri/derleyiciler/CPU'lar arasında deterministik davranmayabilir.

C'de optimizasyon karşılaştırması

Aşağıdaki C programları ve beraberindeki derlemeler, volatileanahtar sözcüğün derleyicinin çıktısını nasıl etkilediğini gösterir . Bu durumda derleyici GCC idi .

Montaj kodunu incelerken, volatilenesnelerle oluşturulan kodun daha ayrıntılı olduğu ve volatilenesnelerin doğasının yerine getirilebilmesi için daha uzun sürdüğü açıkça görülmektedir . volatileDerleyici uçucu nesneler ile kod optimizasyonu gerçekleştirirken anahtar kelime önler, böylece her uçucu değişken atama ve okuma, bir karşılık gelen bellek erişimi sağlamak. volatileAnahtar sözcük olmadan derleyici, bir değişkenin her kullanımda bellekten yeniden okunması gerekmediğini bilir, çünkü bellek konumuna başka bir iş parçacığından veya işlemden herhangi bir yazma işlemi yapılmamalıdır.

C++11

Göre C ++ 11 , ISO Standardı, uçucu anahtar kelime sadece donanım erişimi için kullanılmak içindir; iş parçacıkları arası iletişim için kullanmayın. İş parçacıkları arası iletişim için standart kitaplık std::atomic<T>şablonlar sağlar.

Java'da

Java programlama dili de vardır volatileanahtar kelimeyi, ancak biraz daha farklı bir amaç için kullanılır. Bir alana uygulandığında, Java niteleyicisi volatileaşağıdaki garantileri sağlar:

  • Java'nın tüm sürümlerinde, tüm geçici değişkenlerin okuma ve yazma işlemlerinde genel bir sıralama vardır (uçucular üzerindeki bu genel sıralama, daha büyük eşitleme sırasına göre kısmi bir sıralamadır (tüm eşitleme eylemleri üzerindeki toplam sıradır )). Bu, geçici bir alana erişen her iş parçacığının , devam etmeden önce (potansiyel olarak) önbelleğe alınmış bir değer kullanmak yerine mevcut değerini okuyacağı anlamına gelir . (Ancak, düzenli okuma ve yazma işlemleriyle geçici okuma ve yazma işlemlerinin göreli sıralaması hakkında bir garanti yoktur, yani bunun genellikle yararlı bir iş parçacığı oluşturma yapısı olmadığı anlamına gelir.)
  • Java 5 veya sonraki sürümlerde, geçici okumalar ve yazmalar , bir muteks edinme ve serbest bırakmaya çok benzer şekilde, önce-olur ilişkisi kurar .

Kullanımı volatilebir kilitten daha hızlı olabilir , ancak Java 5'ten önceki bazı durumlarda çalışmayacaktır. Uçucunun etkili olduğu durumların aralığı Java 5'te genişletildi; özellikle, iki kez kontrol edilen kilitleme artık doğru şekilde çalışıyor.

C#'da

In C # , volatilealan erişen bu kod derleyici, CLR, ya da donanım ile gerçekleştirilebilir bazı iş parçacığı güvenli olmayan optimizasyonlar tabi değildir garantiler. Bir alan işaretlendiğinde volatile, derleyiciye çevresinde bir "bellek bariyeri" veya "çit" oluşturması talimatı verilir, bu da alana bağlı talimatların yeniden sıralanmasını veya önbelleğe alınmasını önler. Bir okurken volatilealanı, derleyici oluşturur Edinme-çit okur diğer engeller ve taşınmasını, diğer konuları da dahil olmak üzere bu alanda, yazar, önce çit. Bir volatilealana yazarken , derleyici bir serbest bırakma çiti oluşturur ; bu çit, alana yapılan diğer okuma ve yazmaların çitten sonra taşınmasını önler .

Yalnızca aşağıdaki türleri işaretlenebilir volatile: Tüm referans türleri, Single, Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Charaltta yatan bir türü ile ve tüm sabit tür Byte, SByte, Int16, UInt16, Int32, ya da UInt32. (Bu hariç değer yapılar , hem de ilkel türde Double, Int64, UInt64ve Decimal.)

volatileAnahtar sözcüğün kullanılması, başvuruyla veya yakalanan yerel değişkenlerle geçirilen alanları desteklemez ; bu durumlarda Thread.VolatileReadve Thread.VolatileWritebunun yerine kullanılmalıdır.

Aslında bu yöntemler, genellikle C# derleyicisi, JIT derleyicisi veya CPU'nun kendisi tarafından gerçekleştirilen bazı optimizasyonları devre dışı bırakır. Garantiler tarafından sağlanan Thread.VolatileReadve Thread.VolatileWritesağladığı güvencelerin bir üstkümesidir volatileanahtar kelime: yerine "yarı çit" üretme (yani bir veri paketi-çit tek talimat yeniden sıralama ve ondan önce gelen önbelleğe önler), VolatileReadve VolatileWrite"tam çit" ürettiğini bu alanın her iki yönde talimatların yeniden sıralanmasını ve önbelleğe alınmasını önleyin. Bu yöntemler şu şekilde çalışır:

  • Thread.VolatileWriteYöntem kuvvetleri alanında değeri, çağrının bir noktada yazılacak. Ayrıca, önceki program siparişi yüklemeleri ve depolamaları çağrıdan önce VolatileWriteve sonraki program siparişi yüklemeleri ve depolamaları çağrıdan sonra gerçekleşmelidir.
  • Thread.VolatileReadYöntem kuvvetleri alanında değeri, çağrının bir noktada okunacak. Ayrıca, önceki program siparişi yüklemeleri ve depolamaları çağrıdan önce VolatileReadve sonraki program siparişi yüklemeleri ve depolamaları çağrıdan sonra gerçekleşmelidir.

Thread.VolatileReadVe Thread.VolatileWriteyöntemler çağırarak tam çit oluşturmak Thread.MemoryBarrierher iki yönde çalışan bir bellek bariyer oluşturur yöntemi. Yukarıda verilen tam bir çit kullanma motivasyonlarına ek olarak, volatiletarafından oluşturulan tam bir çit kullanılarak çözülen anahtar kelimeyle ilgili olası bir sorun Thread.MemoryBarrierşu şekildedir: yarım çitlerin asimetrik doğası nedeniyle, volatileyazma talimatı olan bir alan ve ardından bir okuma talimatı, derleyici tarafından değiştirilen yürütme sırasına sahip olabilir. Tam çitler simetrik olduğundan, kullanırken bu sorun olmaz Thread.MemoryBarrier.

Fortran'da

VOLATILEFortran 2003 standardının bir parçasıdır , ancak önceki sürüm onu ​​bir uzantı olarak desteklemiştir. Tüm değişkenleri volatilebir fonksiyonda yapmak, aynı zamanda ilgili hataların aliasing'ini bulmakta da yararlıdır .

integer, volatile :: i ! When not defined volatile the following two lines of code are identical
write(*,*) i**2  ! Loads the variable i once from memory and multiplies that value times itself
write(*,*) i*i   ! Loads the variable i twice from memory and multiplies those values

Her zaman bir VOLATILE'ın belleğine "delinerek", Fortran derleyicisinin okumaları veya yazmaları uçuculara yeniden sıralamasını engeller. Bu, bu iş parçacığında yapılan eylemleri diğer iş parçacıklarına görünür kılar ve bunun tersi de geçerlidir.

VOLATILE kullanımı optimizasyonu azaltır ve hatta önleyebilir.

Referanslar

Dış bağlantılar