Multithreading | std::mutex - 1

Mutex (mutual exclusion)  işletim sistemlerinde olan bir senkronizasyon nesnesidir. Bir mutex'e ayni anda sadece bir thread sahip olabilmektedir. Multithreading sistemlerde deadlock 'lari ve race condition 'ları  engellemek icin kullanilan bir senkronizasyon nesnesidir.
Mutex bir thread tarafından ele alınır ve mutex’in sahipliğini alan thread'ten başka bir thread bu mutex’i ele almaya çalışınca bloke olur. Mutex’in sahibi olan thread mutex nesnesini bırakana kadar diğer thread bekleme moduna geçer. 


Yukarıdaki örneğe bakılırsa 10 tane thread 'lik havuz oluşturulmuş ve daha sonra join edilmiştir. Fakat std::vector veri yapısı burada thread'ler arasında senkronizasyon amaçlı olarak korunmadığı için aşağıda görülebileceği üzere program hatayla sonlanmıştır. 


Thread'ler eğer bir veri yapısını ortak olarak kullanmaları gerekiyorsa senkronizasyon nesnelerinden faydalanmak gerekmektedir. Bundan sonra yazının sonuna kadar senkronizasyon nesnesi olarak mutex 'leri kullanacağız.


Yukarıdaki örnekte mutex 'in içsel fonksiyonu olan lock() ile thread mutex nesnesini kilitler veya başka bir thread tarafından kilitlenmiş ise istek gönderen thread beklemeye alınır.


Yukarıdaki örnek çalıştırıldığında görebileceğiniz üzere program hatasız çalışıyor ve her thread istenen ekleme işlemini gerçekleştirdiği görülebilir. Ama thread önceliği gibi bir kısıtlama olmadığı için aynı program tekrar çalıştırıldığında ekleme sıralamasının farklı olduğu görülebilmektedir.


Yukarıdaki örnekte ise mutex nesnesinin lock/unlock işlemleri std::lock_guard ile sağlanmıştır. Bu sayede mutex'in unlock mekanizmasını unutmak diye bir hatanında önüne geçilmiş olmaktadır.


Yukarıdaki örnekte ise mutex nesnesinin lock/unlock işlemleri std::unique_lock ile gerçeklenmiştir. std::unique_lock sınıfının constructor'ının ikinci parametresine std::defer_lock parametresi geçilerek construction aşamasında mutex'in lock işleminin yapılmamasını sağlayabiliriz. Daha sonra bu işlemi unique_lock sınıfının lock() ve unlock() fonksiyonlarıyla yapabiliriz. Bu noktada eğer unlock işlemini unutursak std::unique_lock sınıfının destructor'ı bizim yerimize yapacaktır.



Multithreading | std::thread - 1

İşletim sistemleri terminolojisinde çalışmakta olan programlara process denilmektedir. Thread'ler için lightweight process'ler denilmektedir. Thread'ler process'lerin farklı çizelgelenen akışlarıdır. İşletim sistemi tüm process'lerin thread'lerini bir çizelgede tutmakta ve bunları zaman paylaşımlı olarak çalıştırılmaktadır. Bir thread biraz çalıştırılmakta sonra çalışmasına ara verilmektedir. Başka bir thread kalınan yerden çalışmaya devam ettirilmektedir. Bir process'in thread 'leri için Stack ve Register değerleri/alanları farklı; Heap, Code, Data ve Files değerleri/alanları ise ortaktır.


C++11 ile gelen std::thread ile multithreading programlama olanakları artmıştır. Aşağıda C++11 ile gelen sınıfın üye fonksiyonları ve diğer özellikler listelenmiştir.


Aşağıda basit bir thread uygulaması yapılmış ve yapılmak istenen işlemler threadler üzerinden yapılmaya çalışılmıştır. Burada join işlemini unutmamız sistemin hata vererek sonlanmasıa neden olacaktır.


Aşağıdaki thread uygulaması ise yapılacak işlemler lambdalar ve functor'lar ile thread'ler üzerinden yapılmaya çalışılmıştır.


Aşağıdaki thread uygulamasında ise fonksiyonlar ve functor'lar ile thread'ler üzerinden parametrelerin nasıl aktarılacağı anlatılmıştır.


Aşağıdaki thread uygulamasında ise thread'ler üzerinden referans yoluyla parametrelerin nasıl aktarılacağı anlatılmaya çalışılmıştır.


Yukarıdaki kodu derleyip çalıştırdığımızda ival değerinin thread tarafından değiştirilmiş olduğunu görebiliriz.


Burada dikkat edilmesi gereken nokta std::ref() fonksiyonunun kullanılmaması aşağıdaki gibi bir hatanın çıkmasına yol açmaktadır. Fonksiyon parametre olarak bir referans istiyor ve bu sağlanmazsa hatayla karşılaşılıyor.


Aşağıdaki thread örneğinde ise bir sınıfın üye fonksiyonunun thread tarafından nasıl çağrılacağına ilişkin örnek kullanım biçimi işlenmiştir.


Sınıf Şablonları (Class Templates)

08:33 ,
Sınıf şablonları da fonksiyon şablonlarında olduğu gibi benzer amaçlar için kullanılmaktadır. Generic programming denilen bu amaç tek bir kod yazıp birden fazla defa kullanılmasına olanak sağlamasıdır. 
Sınıf şablonu örneği - 1
Sınıf şablonlarına ilişkin örnek kod yazımı sırasında görebileceğimiz üzere çok sık kullandığımız container'lar aslında birer template sınıf şablonlarıymış. Örneğin: std::vector<int>, vb  
Biz de STL container'larına benzer şekilde tek bir stack template sınıf şablonu kodu üzerinden birden fazla biçimde stack türü oluşturabilmemize olanak sağlamış olduk.

Sınıf şablonu örneği - 2

Yukarıdaki örnektede benzer şekilde bir dizi şablonu oluşturulmuş ve farklı iki biçimde kullanımına olanak sağlanmıştır. Burada template yazarken int N diyerek bazı türleri sabit türde yazabilme olanağı olduğunu gözden kaçırmamak gerekir.

Fonksiyon Şablonları (Function Templates)

06:27 , ,
Template'in kelimesinin anlamı şablon ve C++'daki function template olarak kullanım şekli de fonksiyonların şablon olarak yazılmasına olanak sağlamasıdır. Bu sayede yazılan fonksiyonun farklı parametre  türlerine  uygun olarak derleyici tarafından istenen biçimlerde yazılmasına olanak sağlamasıdır. Bu sayede C'de olduğu gibi bir fonksiyonu farklı farklı tipler için ayrı ayrı yazmak yerine, tek bir  fonksiyon şablonu yazıp  bunu farklı farklı tipler için kullanım esnekliği sağlamaktadır.

template <typename T>
return-type func-name(parameter list) {
   // body of function

Template yazarken tip oluşturmak için typename veya class anahtar kelimesi kullanılabilir. İkisi de aynı anlama gelmektedir. Ama class kelimesinin kullanılması yanlış anlamlara çıkabileceğinden dolayı typename kelimesini kullanmak daha doğru olacaktır.

Function Template Örneği

C++11 ile gelen Variadic Function Template örneği ise aşağıdaki gibidir. Temelde şablon fonksiyonların parametreleri sabit ama veri tipleri değişkendir. Fakat variadic versiyonunda ise parametre sayısı da değişken biçimdedir. Bu konu şimdilik bir örnekle açıklansa da daha sonra başlı başına bir yazının konusu olacaktır.


Variadic Function Template Örneği
Fonksiyon şablonlarına parametreleri değer veya referans yoluyla geçilmesine ilişkin oluşabilecek problemleri içeren bir kod örneği aşağıda verilmiştir.


Eğer kodun içinde <int&> kısmını kaldırırsak aşağıdaki gibi bir hatayla karşılaşırız. Bunun nedeni type deduction yaparken compiler ilk parametreye bakarak T türünün int olduğunu düşünmekte fakat ikinci parametreye baktığında ise T türünün int& olduğuna karar vermekte ve hata mesajıyla karşılaşılmaktadır. Bu nedenle compiler'a T türünü doğrudan söyleyerek problemi aşabiliriz. 


Yazdığımız template için compiler'ın deduction yapmadan doğrudan kendimiz türünü bildirmek için de yukarıdaki örneğe benzer şekilde fonksiyonun yanına <int,double, ...> biçiminde belirtebiliriz.

Note:

  • Template fonksiyonumuzdaki parametreleri ve geri dönüş tipini referans yapmak daha iyi  performans sağlanmasına yardımcı olacaktır.