C#’ta volatile Anahtar Sözcüğü

Merhaba,
C# dili, yapısal olarak diğer diller gibi bir gramere ve bu gramer çerçevesinde inşa edilebilir yapılara ve bu yapıları oluşturmamızı sağlayan temel yapı birimleri diye nitelendireceğimiz kodlara sahip geniş ve hatta derya deniz diyebileceğimiz bir programlama dilidir. Dilin hakimiyetini sağlayabilmek için bu üç açıdan da içi dolu bilgi ve tecrübe gerektiren yazılım zanaatkarlığında işte bu şartlar yerini bulduğunda işin kurmayı kıvamına gelinebilmektedir.

Haliyle bizde kurmaylık yolunda bir adım daha atabilmek için volatile keywordü üzerine derin ve detaylı bir içerik oluşturacak ve C# dilinde çok nazik bir noktaya temas eden bu anahtar sözcüğün sizlere kafiyesini tattıracağım.

Başlamadan önce içeriğimizde; değişkenlerin okunması yahut tekrar yazılması durumlarında microişlemlerin nasıl bir mantıkta hareket ettiği ve bu seyrin asenkron bir altyapıda nelere mal olabileceği üzerinde konuşacağımızı bildirir, kısaca değişkenlerin okunması, microişlemcinin süreçteki algoritması ve asenkron çerçevede bu durumların değerlendirmesini ele alacağımızı bilmenizi ister ve bu ön bilgilere dönük beklentiyle içeriği okumanızı tavsiye ederim.

Şimdi öncelikle şunu bilmenizi istiyorum. Bir program yazdınız ve program içerisinde değişkenleriniz var. Mikroişlemci, ilgili değişkenleri kullanırken her defasında daha hızlı ve pratik olabilmek için bu değişkenleri bellekten almak yerine kendi içerisinde sınırlı sayıda bulunan Data Register diye nitelendirilen kayıtçılara bu değişkenleri değerleriyle birlikte kaydeder ve burada tutar.

Burada şu soruyu soralım. Değişkenlerin, bellekte ya da data registerda tutulmasının farkı ve faydası nedir? Sorunun tek cevabı hız ve performanstır.

Mikroişlemci bir değişkene data registerdan, belleğe oranla kat kat hızlı erişebilir ve yüzden böyle bir çalışma gerçekleştirir. Hem herhangi bir T zamanda tek işlem yapabilecek mikroişlemciler için bu olmazsa olmaz bir alternatif değil midir?

Bu çalışma düzeneğinin bir diğer boyutu, yukarıda bahsettiğim gibi data register alanında sadece salt değişkenler değil, onların değerleride tutulmaktadır. Derleyici, bazı değişkenlerin değerini her defasında bellekten okuyacağına bu değişkenin değerini bir defaya mahsus data register alanına kaydedebilir. Dikkat ederseniz kaydettiği bu değeri sonraki çağrımlarda bellekten değil bu data register üzerinden getirebilmektedir. Evet, hal böyleyken mükemmel bir performans ve hız kazancı söz konusu olacaktır.

Ammaaaa!!!

Siz hiç bu kadar ucuz hız ve performans gördünüz mü? Yazılımda her artının bir bedeli olduğu gibi bu mekanizmanında bir aması vardır.

Düşünün ki, herhangi bir T zamanda data registera kaydedilen bir değişken herhangi bir T++ zaman çağrıldığında data registerdaki kayıttan gelecektir. Evet, bir sıkıntı gözükmüyor. Peki olayı şöyle düşünürsek, herhangi bir T zamanda data registera kaydedilen bir değişkenin değeri herhangi bir T++ zamanda değiştirilmekte lakin bu değişiklik anında data registera yansıtılmama ihtimali olduğundan herhangi bir T+++ zamanda değişkenin değeri çağrıldığında eski değeri getirme ihtimali olacaktır.

Eee… Olur mu böyle birşey!!!? Biz yazdığımız programları insanlardan daha hızlı işlem yapabildikleri ve veri organize edebildikleri için derlemiyor muyuz? Yazacağım bir programın anlık güncel verileri taşıyamaması yahut o verilerle çalışamaması sonucunda ne anlarız öyle yazılımdan…

Her neyse… Konumuza dönelim…

Yukarıda yazmış olduğum son paragraftanda çıkarabileceğimiz gibi nasıl oluşturulan değişkenler değerleriyle birlikte bellekten data registera taşınıyorlarsa, aynısını değişkenin değerini değiştirdiğimiz durumda da gerçekleştirmektedirler. Ama bu değiştirme durumunda bir gecikme söz konusu olabilir. Örn; 3. satırda yapılan bir değişiklik 5. satırda data registera yansımış olabilir. Ee haliyle artık çok geç olmuşta olabilir… Bu gecikme süresi mikroişlemcinin o anki durumuna göre değişkenlik göstermektedir.

Bu mekanizma karşısında birde madolyonun öteki yüzü var ki zaten iş genellikle burada kopuyor. Multi Thread temelli yani asenkron çalışmalarda farklı processler kendi aralarında değişkenleri kullanabilmektedirler. Ya da bir iş parçacığı(Thread) farklı bir iş parçacığının kullandığı değişken üzerinde işlemler gerçekleştirebilir.

İşte bu tarz kutupsal çalışmalarda yukarıdaki olası gecikmeli durumu genelleyiniz. Durun size bu konuda tahayyül edebilmeniz için yardımcı olayım.

Asenkron çalışıyorsunuz…
Yani senkron bir işlemden daha kompleks ve yönetilebilirliği zor bir durumdasınız…
Satır satır değil, bütünsel hareket ediyorsunuz…

Eee işte böyle bir durumda, yukarılarda bahsettiğimiz gibi senkron olarak tasarlanmış bir programdaki değişkenlerde olası gecikmeli data register kayıtlarında çalışma ihtimalimizdeki (olasıdır ama çok düşük bir ihtimaldir)zayıflık, asenkron yaklaşımda güçlenmekte ve artık farklı bir kontrol ile çalışma gerektirmektedir.

Yok eğer kontrol sağlayamazsak farklı thread yahut processler aynı değişken üzerinde çalışırken ilgili değişkenin değerini bellekten değil gene data registerdan alacaktırlar. Ama bu süreç esnasında data registera yansımamış güncellemeler gerçekleşmiş olabilir lakin böyle bir olası durumda biz yazılımcıların bu son değerden bi haber olacağımız kesindir. Derleyici bir değişkenin değerinin farklı thread yahut processler tarafından işleneceği üzerinde durmayacaktır. Bu işlem işletim sisteminin yönetiminde olduğu için bu konuda ilgili birimlerden pek fazla beklentide olmamız doğru olmayacaktır.

Peki alabileceğimiz önlem ve yapabileceğimiz kontrol nedir?
Asenkron yaklaşım sergilerken yapmamız gereken tek işlem thread yahut processlerin ortak çalıştığı değişkenin değerinin bellekten gelip gelmediğini bilmektir. Tabi ki de tercihimiz bellek olacaktır. Çünkü yapılan tüm güncelleme ve değişiklikler direkt olarak anlık belleğe yansıyacağından dolayı işte bu tarz durumlarda doğru bir seçim olacaktır. Bu şeçimide içeriğimizin asıl konusu olan volatile anahtar sözcüğü ile gerçekleştirebilmekteyiz. Yani volatile keywordü bunca anlattığım durum üzerine bizim kontrol yapmamızı sağlayacak anahtarımız olacaktır.

Volatile keywordü, işaretlediği değişkenin data register optimizasyonuna uğramadan direkt olarak bellek üzerinden temasını gerçekleştirir. Yapılan güncellemeler anlık belleğe yansıyacak ve son güncellemeler ne ise onlarla çalışılacaktır. Hız imiş, performans imiş kârdan zarara uğrayacaktır. Eee haliyle asenkron alt yapıda farklı thread yahut processler aynı değişken üzerinde yoğunlaştığında direkt olarak bellekten beslenecekleri için son veri kaygısı yaşanmayacak, gönül rahatlığıyla çalışılabilecektir.

volatile keywordünün, sanıldığı üzere yaz geç usulü kullanılmaması gereken ve bilakis epey ayrıntılı ve dikkatli olunması gereken bir konu olduğuna dikkatinizi çekerim.

Şimdi volatile üzerine pratik örnekler inceleyelim.

    class Program
    {
        volatile bool x;
        volatile int y;
        string z;
    }

Kod bloğunda gördüğünüz gibi volatile ile işaretlenmiş değişkenler direkt olarak bellekten beslenmekteyken işaretlenmeyenler data register mekanizmasıyla çalışmaktadırlar.

Ayriyetten bilmenizi istediğim volatile keywordü class scopeu içerisinde oluşturulan değişkenlerde kullanılabilmektedir. Metod yahut property içerisinde oluşturulan değişkenlerde kullanılamamaktadır.

    class Program
    {
        volatile static bool Durum;
        volatile static int Sayi = 1;
        static void Main(string[] args)
        {
            Thread t = new Thread(new ThreadStart(() =>
            {
                Sayi = 5;
                Durum = true;
            }));
            t.Start();

            while (true)
            {
                if (Durum)
                {
                    Sayi += 5;
                    Console.WriteLine(Sayi);
                    break;
                }
                Console.WriteLine(Sayi);
            }

            Console.Read();
        }
    }

Yukarıdaki örnek kod bloğunu incelerseniz eğer Durum ve Sayi değişkenleri volatile olarak işaretlenmekte ve ilgili değişkenler farklı bir Thread tarafından dahi bellekten dinlenmektedirler.

Evet…
Gördüğünüz gibi dilin bazı keywordleri şudur demekle izah edilememekte, olası olaylar zincirini senaryolaştırılıp bir şekilde somutlaştırabildikten sonra fazla örnek verme imkanı olmadan kestirilmek mecburiyetindedir.

Umarım faydalanırsınız…
Okuduğunuz için teşekkür ederim…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim…

Bunlar da hoşunuza gidebilir...

4 Cevaplar

  1. Cem dedi ki:

    Teşekkürler Sn Gencay,
    Gayet güzel bir açıklama olmuş.
    Cem

  2. erhan dedi ki:

    On numara makale,emeğine sağlık.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*

Copy Protected by Chetan's WP-Copyprotect.