Günümüz internet altyapısı incelendiğinde dağıtık uygulama
senaryolarında işlemlerin belirlenen süreçler yerine anlık altyapı yoğunluğuna
göre değişiklik gösterdiğini rahatlıkla anlayabiliriz. Bu noktada işlemin
gerçekleştiği süreç esnasında uygulamanın o an görünen ekranının kilitlenmesi
yerine Asenkron Mimari üzerinden bir uygulama dizaynı uyguladığımızda işlemin
uygulama process’ i içerisinde farklı bir thread (şerit) üzerinden
çalıştırıldığını ve işlemin çalıştığı süreç esnasında uygulamamızın normal
seyrinde çalışıyor olmasını sağlayabiliriz. Bu noktada mimarinin
uygulanabilmesi için farklı yöntemler söz konusudur. Bunlardan ilki işlemin
uygulama içerisinde tanımlananan yeni bir thread içerisinde çalıştırılması iken
bir diğeri ise –ki yönetimi çok kolay olmakla birlikte aslında arka tarafta
aynı kapıya çıkmaktadır- delegelerin kullanılması ile sağlanan çözümdür. Bu
makalemizde “Mobil Cihazlar” üzerinde threadleri kullanarak Asenkron Mimari
üzerinde nasıl çalışacağız bu konu ile ilgili açıklayıcı bir örnek
geliştireceğiz.
Örneğimize başlamadan önce basit bir senaryo üzerinde
yoğunlaşalım. Mobil Cihazlarında kullanıldığı dağıtık bir uygulama senaryosu
geliştirelim. Bir ilaç şirketinde çalışan ve sahada gün içerisinde merkez ile
ellerindeki Pocket PC’ ler üzerinden iletişim kuran saha elemanları. Bu noktada
elemanın bulunduğu nokta, baz istasyonu ile arasındaki bağlantının tutarlılığı
v.b. gibi birçok etken bağlantı kurulduktan sonra gerçekleştirilen işlemin sonlandırma
sürecini önemli ölçüde etkilemektedir. Bu noktada saha elemanının merkez nokta
üzerinde bağlantı kurmak istediği zaman sürecinde bu işlem sonlanana kadar
mobil cihazı üzerinde bulunan uygulamayı kilitlenmeden kullanabilmesi diğer
işlerin gerçekleştirilmesi açısından önemli bir etkendir. İşte bu noktada
Asenkron Mimari devreye girmektedir. Geliştirecek olduğumuz örnek uygulama
üzerinde böyle bir uygulama senaryosunu gerçekleştiremediğimizden aynı
kilitlenme ortamını oluşturabileceğimiz klişe bir örnek üzerinde konuyu
inceleyeceğiz. 20000 adet sayının bir liste kutusuna yazdırıldığı süreci ele
alalım. Aynı problem bu noktada yine yaşanacaktır. Sayıların listelenmesi
süresince uygulamanın ana ekranı üzerinde herhangi bir işlem
gerçekleştirilemeyecek ; belkide uygulama kilitlenip sonlanacaktır.
Daha fazla vakit kaybetmeden uygulamımızı geliştirmeye
başlayalım. Konu ile ilgili çalışabilmek için bir C# Smart Device Windows
Application projesi açıyoruz.

Bir sonraki adımda şekilde görülen basit formu tasarlıyoruz.
Formumuzun üzerinde bir buton birde Liste kutusu kontrolü yerleştiriyoruz.

Amacımız listele butonuna bastığımız noktada liste kutusu
içerisine 20000 adet sayının listelenmesi. Kulağa basit gelmekte olabilir. Ama
sayı miktarının fazla olması bu noktada uygulamanın Asenkron Mimari üzerinden
geliştirilmesi gerçeğini ortaya çıkarmaktadır. Bu noktada önce standart
yaklaşımla şekildeki kod bloğunu geliştiriyoruz.

Sıra geldi uygulamamızı bu haliyle çalıştırmaya. F5’ e
basarak projemizi çalıştırıyoruz ve Button’ a tıkladığımız zaman uygulamanın
ana ekranının kitlediğini çok rahat bir şekilde analiz edebiliriz. Eğer bu
noktada formumuzun üzerinde görsel açıdan farklı amaçlar için yerleştirilmiş
Windows Form kontrolleri bulunsaydı bu kontroller üzerinde işlem sonlanana
kadar kesinlikle bir değişiklik yapamayacak ; haliyle işlemin sonlanmasını
beklemek zorunda kalacaktık. Uygulamanın çalışır haldeki görüntüsü şekildeki
gibidir.

Şekildende farkedilebileceği üzere Scrollbar’ ın küçük olmasına
rağmen (yani sayılar listelenmesine rağmen) ekranın kilitli görünümünden ötürü
bu sayıları uygulamamız gösterememektedir. Peki çözüme nasıl ulaşacağız ?
Yazının başındada belirttiğimiz gibi Asenkron Mimari
kullanarak bu probleme çözüm bulabilir. Bu noktada Asenkron Mimariyi bir
uygulama üzerinde uygulayabilmemiz için birçok farklı yöntem bulunmaktadır. Fakat
.NET Compact Framework’ ün ise bu konuda bazı sıkıntıları bulunmaktadır. Bunlardan
en önemlisi uygulama geliştiriciler .NET Compact Framework üzerinde delegeleri
kullanarak Asenkron Mimariye sahip uygulamalar geliştirememektedirler. Olaya bu
açıdan baktığımızda kullanılabilecek tek yöntem System.Threading namespace’ i
içerisinde bulunan Thread sınıfınından yararlanmak olacaktır.
Thread sınıfı, adından da anlaşılabileceği üzere Process’
lerin temel birimi olan Thread (Şerit)’ ler ile ilgili çalışmak üzere
tasarlanmış bir sınıftır. Arkada tarafta işletim sistemi üzerinde tanımlı bir
çok metodu Managed ortamda uygulama geliştiricilere çok daha kolay bir arayüz
üzerinden sunmaktadır. Bu noktada .NET Compact Framework üzerinde tanımlı olan
Thread sınıfı standart Thread sınıfının gerekli olan tüm metotlarını bünyesinde
barındırmaktadır.

Sınıfın metot ve özelliklerine baktığımızda bir önceki
paragrafta anlatıldığı üzere gerekli ve yeterli olan tüm yapıların hazır olarak
geldiğini rahatlıkla anlayabiliriz.
Bu makalemizde örneklenen uygulamada yaşanan sorun daha
öncede anlatıldığı üzere, uygulama process’ i başlatıldığında bu process’ in
içerisinde o noktadan sonra yürütülecek olan tüm işlemlerin çalıştırılacağı
Main (Ana) bir Thread istesekte istemesekte oluşturulmaktadır. Application.Run
metodu ile uygulamamızın başlayan yaşam süreci içerisinde işletim sistemi
üzerinen gelen mesajlar sırasıyla işletilmektedirler. Bu noktada yaşanan
problem döngü içerisinde “döngü sonlanana kadar” her yeni değerde yeni bir
mesaj gelmekte ; işletilmekte ve haliyle uygulama içerisinde gönderilen diğer
mesajlar bekletilmektedirler. Bunun sonucunda ise işlem sonlanana kadar
uygulama ekranımız “kilitlenmektedir”. Amacımız bu işlemleri Main (Ana) thread’
in dışında yeni bir Worker (İşçi) thread kullanarak uygulamanın temel thread’ i
dışında çalıştırarak ; uygulama ana ekranının gönderilen diğer mesajların
çalıştırabilmesini ; başka bir deyişle kitlenmemesini sağlamaktır. Hiç vakit
kaybetmeden makalemize kaldığımız yerden devam edelim. Amacımız bir önceki
cümlede de ifade ettiğimiz üzere işi gerçekleştirecek Worker (İşçi) bir thread
tanımlamak olacaktır.

Kod ile ilgili “ayrıntılı” bir açıklamanın bu noktada
gerekli olduğundan satırların numaralandırılmış olması daha doğru olacaktır.
İlk olarak 18 numaralı satır üzerinden geliştirdiğimiz kod
bloğunu açıklamaya geçelim. Bu satır içerisinde System.Threading.Thread
sınıfının th isminde null bir referansını oluşturmaktayız. Bu null referansı
Form1_Load metodu içerisinde System.Threading.Thread sınıfının bir instance’
ına eşitliyoruz. Ki bakacak olursak bütün olay bu satırda ; yani 21 numaralı
satır içerisinde halledilmektedir.
Thread sınıfının Constructer’ ına baktığımızda, sınıf,
uygulama geliştiriciden System.Threading.ThreadStart tipinde bir delege
instance’ ı istemektedir.
Sınıfın bu delegeyi istemesinin temel sebebi çalıştıracak
olduğu metodun adresine ihtiyaç duyduğu zaman çekebilmesi içindir. Bu noktada
ThreadStart delegesi sadece “parametre almayan” ve “void geri dönüş değerine
sahip” bir metodu adresleyebilmektedir. Bu sebeple 26. Satırdan itibaren
Saydir() isimli parametre almayan ve void geri dönüş değerine sahip bir metot
tanımlanmıştır. Döngümüz ise bu metot içerisinde ise çalıştırılmaktadır. Bu
noktada 30. Satırda kontrolün Items koleksiyonu içerisindeki standart Add
metodunun neden kullanılmadığına değinmek çok doğru olacaktır.
Bilindiği üzere asenkron mimariye sahip uygulamalarda Worker
(İşçi) thread üzerinden farklı bir thread üzerinde oluşturulmuş bir objenin
herhangi görsel bir değerini değiştirememekteyiz. Böyle bir durumda
CrossThreadOperationException tipinde ifade edilebilecek bir hata kaçınılmaz
olacaktır. Bu noktada kontrolün Invoke metodu ile işlemi lstSAYILAR isimli
Liste kutusununu oluşturulduğu Main (Ana) thread üzerine geçirmekte ; sayı ekleme
işlemini bu lokasyonda gerçekleştirmekteyiz.
Biraz daha yakından incelediğimizde ise Invoke metodu da
Thread sınıfının istediği türe benzer bir türden çalıştıracak olduğu metodun
adresini alabilecek bir delege istemektedir. Fakat bu noktada elimizde hazır
bir delege bulunmadığından ListBox kontrolünün Items koleksiyonu içerisinde
bulunan Add metodu ile aynı geri dönüş değeri ve parametre yapısına sahip bir
deleyi kendimiz oluşturup, bunun bir kopyasını lstSAYILAR.Items.Add metodunu
adresleyerek Invoke isimli metoda değer olarak göndermekteyiz.
Tüm bu adımlar başarılı bir şekilde gerçekleştirdikten sonra
36. Satırda yani btnSAYDIR button’ una tıkladığımızda th isimli Thread objesi
referansı üzerinden Thread’ i çalıştırmaya başlatıyoruz. Hepsi bu kadar !

Uygulamayı çalıştırıp Saydır button’ una bastığımız zaman
sonuç tek kelimeyle mükemmel ! Saydırma işlemi devam ederken ScrollBar hareket
ettirilebilir durumda olmakla birlikte ekran üzerindeki diğer kontroller işlemin
bitmesini beklememektedir ; kullanıma açık durumdadır !
Bu makalemizde Mobil cihazlar üzerinde
System.Threading.Thread sınıfını kullanarak asenkron işlemler nasıl
gerçekleştirilir bunun üzerinde ayrıntılı bir örnek geliştirdik.
Başka bir makalede daha görüşmek üzere.