Haftalık C++ 44 – Aktif Nesne Tasarım Örüntüsü

Evet sevgili yazılımperver dostlarım, 2021 bitmeden sizler ile terkar birlikteyiz. Bu yazımızın konusu Aktif Nesne tasarım örüntüsü.

Eminim bir çoğunuz temel bir çok tasarım örüntülerini duymuşssunuzdur: “Singleton”, “Factory” ya da “Observer” gibi. Eğer bunları duymadıysanız (ki bunlara ben de 2022’de inşallah C++ perspektifinden eğileceğim), sizlere bu konudaki mihenk taşı olan bir kitaba göz atmanızı önereceğim: “Design Patterns: Elements of Reusable Object-Oriented Software. Bu kitap içerisinde temel tasarım örüntüleri, Yaratma (“Creational”), Yapısal (“Structural”) ve  Davranışsal (“Behavioral”) olarak gruplandırılarak, dilden bağımsız bir şekilde anlatılmakta.

Aktif nesne tasarım örüntüsü ise aynı anda kullanım “Concurrency” ya da multi-threaded uygulamalar için kullanılabilecek bir örüntüdür. Neyse, konuyu daha fazla uzatmadan önce tanıma daha sonra da örnek uygulamaya bir göz atalım.

Eğer, multi-threaded kod geliştiriyorsanız ya da IBM Rhapsody kullanmışsanız, aktif nesne örüntüsünü muhakkak duymuşssunuzdur ya da farkında olmadan zaten kullanıyor da olabilirsiniz 🙂

Peki nedir bu aktif nesne örüntüsü?

Aktif nesne tasarım örüntüsü, bir fonksiyon/metot çağrısını, çağrılan thread’ten ayırarak bağımsız hale getirerek, kendi kontrolündeki thread’te koşarak, kotarmasını sağlar.

Bu örüntünün temel amacı, metot çağrısını ayrı bir thread’e alarak aynı anda çalışmayı ve asenkron gelen istekleri kotarabilmektir. Bir diğer ifade ile, güvenilir ve eşzamanlı bir çalışmaya olanak sağlayan bir modeldir. Tipik bir aktif nesne örüntüsü, bir tür harici API, bir thread-safe kuyruk ve gerekli davranışı yürütmek için bir iş parçacığı (thread) içerir. Aşağıda, basit bir şekilde bu örüntüye ilişkin bileşenler tariflenmiştir:

Aktif nesne örüntüsü, UML içerisinde de kullanılmakta ve bu özelliğe haiz sınıflar Aktif Sınıf olarak aşağıdaki gibi işaretlenmektedir. Bu da, ilgili sınıfların, kendine ait koşumları, kendilerinin yönettiği anlamında gelmektedir.

An active UML Class element.

IBM Rhapsody içerisinde de, bu şekilde işaretlenen sınıflar, benzer şekilde ayrı bir thread içerisinde koşulmakta, aynı zamanda bu sınıflar, tanımlanan durum diyagramları ile de bağımsız bir şekilde gelen olayları kotarabilmektedir. Aktif nesnelerin, durum diyagramları ile kullanımına ilişkin Miro Samek’in çok güzel yazısına göz atmanızı tavsiye ederim.

Yukarıda basit bir aktif nesneyi tarifledik. Orjinal örüntüye ilişkin yayında ise, daha kapsamlı ve detaylı bir örüntü tariflenmekte. Dileyen (aslında herkesin 🙂 ) yazılımperver dostlarımın bu yayına da bakmalarını rica ediyorum. Aşağıda, bu yayında verilen örüntünün bileşenlerine ilişkin figürü görebilirsiniz.

Sonuç olarak, herhangi bir şekilde C++ uygulaması geliştiriyorsanız, Herb Sutter’in de şu yazısında bahsettiği gibi, çıplak thread’leri kullanmak yerine, aktif nesneleri kullanmalısınız. Bu sayede aşağıdaki faydaları elde ediyor olacağız ki büyük ölçekli bir uygulamada bunların önemini kesinlikle küçümsememelisiniz:

  • Uygulamanın eşzamanlılığını arttırırken, senkronizasyon karmaşıklığını düşürmek,
  • Donanımdan sağlanan paralellikten üst düzeyden yararlanma ve birden fazla aktif nesneyi paralel bir şekilde çalıştırma (eğer donanım/yazılım platformu birden çok CPU’yu destekler ise),
  • Her nesneye özgü verinin izole edilmesi.

Bu arada paralellik (parallelism) ve aynı anda kullanım (concurrency) konusunda bir hatırlatmaya ihtiyacınız var ise aşağıdaki yazıma bir göz atabilirsiniz.

Haftalık C++ 7- std::thread (I)

Evet sanırım örüntünün ne olduğunu, ne için kullanıldığını bize neler getirdiğini anladık. Arka sıralardan gelen “Kod! Kod! Kod!” çağrılarını artık daha fazla yanıtsız bırakmayıp, örnek aktif nesne sınıfına bakalım 🙂 Örneğimizi, C++ 11 ile basit bir sınıf olarak oluşturacağız. Bu sınıf, std::function sayesinde, kendisine sunulan lambda, functor ya da benzeri işlevleri, aktif nesne içerisinde kotarabilmektedir. Bu sınıfı ayrıca kullanan basit bir sınıf da ekliyoruz.

Örneğe ilişkin detaylar için Herb Sutter’in sayfasına göz atabilirsiniz.  Örnekte kullandığım, thread-safe queue, yukarıdaki aktif nesne ve diğer örnek kodlara aşağıdaki bağlantıdan ulaşabilirsiniz. Lütfen geri bildirimlerinizi benimle paylaşın.

https://github.com/yazilimperver/CodeSnippets/tree/main/Utilities 

Evet arkadaşlar, mult-threaded kodlarınızda, de facto, kullanacağınız bir örüntü ile 2021 yılını kapatıyoruz. Peki, yukarıdaki sınıfa daha başka ne ekleyebiliriz? Zamanlayıcı olayları, dönüş değeri, aktarılan işlerin önceliklendirilmesi, durum diyagramı kullanımı ve bir çoğu mümkün. Bunları da, gerçekleştirdikçe sizler ile paylaşıyor olacağım, ama sizler için de iyi bir egzersiz fırsatı olabilir.

Bir sonraki yazımda görüşmek dileğiyle, bol kodlu yıllar diliyorum 🙂

Kaynaklar

Bir cevap yazın

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

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.