Vücudumuzda, yaşamamızı devam ettirebilmemiz için aynı anda birçok görev birbirine paralel bir şekilde gerçekleştirilir. Solunum, kan dolaşımı, enerji üretimi, her an, her saniye birbirleriyle uyumlu bir şekilde devam eder. Aynı durum bilgisayarlarımızda da söz konusudur. Bir taraftan müzik dinlerken, diğer taraftan internetten dosya indirebilir, bunların yanında yazıcımızdan çıktı alabilir, favori kelime işlemcimizde yazı yazıyor olabiliriz. Hatta tek bir program dahi birçok işi eş zamanlı olarak gerçekleştirebilir. Örneğin kelime işlemcimizde yazı yazarken, programımız, yazdıklarımızı biçimlendirmekle ne kadar meşgul olursa olsun, klavye ve fareyle yaptığımız işlere her zaman duyarlıdır. İşte aynı anda birden fazla görevi gerçekleştirebilen yazılımlara eş zamanlı (concurrent) yazılımlar, bu görevlerin eş zamanlı gerçekleştirilmesine de eş zamanlılık (concurrency) diyoruz. Bu da bizi asıl konumuza getiriyor: multithreading, yani çok kanallılık. Çok kanallılığın tanımını yapmadan önce iki terimi bilmekte yarar vardır: işlem (process) ve kanal/işlemcik/izlek (thread).

İşlem (process): Kısaca çalışmakta olan program demektir. Kendi bellek alanları, işlemci durumu kayıtları ve çalışma zamanı kaynakları (run-time resources) olan uygulama ortamlarıdır. Çoğu zaman program ve uygulama (application) kelimeleriyle eş anlamlı olarak da kullanılırlar. Ancak kullanıcının gördüğü tek bir uygulama, birçok işlemden oluşmaktadır. İşlemcik (thread): İzlek veya kanal olarak da anılır. Çoğu zaman hafif işlemler olarak adlandırılırlar; ancak sistem gereksinimleri işlemlere göre daha düşüktür; çünkü kendi işlemci durumu kayıtları olmasına rağmen, sistem kaynakları ve bellek alanlarını yaratıldıkları işlemden alırlar. Bir işlemin eş zamanlı görevleri gerçekleştirebilmesi amacıyla yazılmış ve genellikle tek bir görevi çalıştıran kod parçalarıdır.

Tanımlarımızı yaptıktan sonra artık çok kanallılığa geçebiliriz. Çok kanallılık, adından da anlaşılacağı üzere birçok işlemcikin eş zamanlı bir şekilde işlem yapabilmesidir; bir başka deyişle, bir işlemi, kendi içinde birbirine paralel biçimde daha küçük alt birimlerle (thread) çalıştırma şeklidir. Bir de çok görevlilik (multitasking) vardır ki, belli yönlerden çok kanallılıktan ayrılır. Çok görevlilik, işletim sisteminin aynı anda birden fazla program çalıştırabilmesidir, ancak gerçek bundan biraz farklıdır. İşletim sistemi, çalışacak programları öncelikle sıraya sokar ve sonra sırası geleni çalıştırır. Bu işlem sonucunda programları aynı anda çalışıyorlarmış gibi görürüz, büyülü bir şey yani :) Ayrıca çok görevlilikte görevler aynı belleği paylaşamazlarken, çok kanallılık’de paylaşabilirler. Çünkü çok görevlilik işlemler üzerinden işlerken, çok kanallılık işlemcikler üzerinden gerçekleşir.

Çalışma Prensibi

Bilgisayarımızda çalışan her bir işlemcik için bellekte belirli bir yer, işlemci tarafından belirli bir zaman ayrılır. Bunlara ek olarak tüm işlemciklerin belirli öncelikleri (priority) vardır. İşletim sistemleri, uygulamalar içinde çalışan işlemcikleri önceliklerine göre sıralayarak çalıştırırlar, ancak bazı yöntemlerle belirli bir dereceye kadar akışları değiştirilerek de kullanılabilirler. Aksi belirtilmedikçe bir işlemcik, başka bir işlemcikin çalışmasına karışamaz, bu yüzden birçok işlemciğin aynı anda, aynı verileri kullanma ihtimalleri vardır ki, bazen bu durum tehlikeli sonuçlara neden olabilir. Bu şekilde birçok işlemcik tarafından paylaşılabilen verilere, “kritik bölge verileri” (critical region) adı verilir. Kritik bölgede birden çok işlemcik çalışıyorsa, işlemciklerin hafızaya ve işleme zarar vermeden çalışabilmeleri için senkronize olmaları şarttır. Örneğin, hatalı ve bilinçsizce yazılan kodlar sonucunda deadlock (kilitlenme) meydana gelebilir. Bu durumda, iki ya da daha fazla işlemcik, birbirlerini bekleyerek, sonsuza kadar çalışabilirler. (Kilitlenmeyle ilgili daha detaylı anlatım için Mayıs sayımızdaki "Ölümcül Kilitlenme" yazımıza göz atabilirsiniz.) Tam tersine, eğer bir işlemcik, paralel çalıştığı diğer işlemciklerin “oyun sahasına” karışmıyor ve onların kritik bölgeleriyle işlem yapmıyorsa bu durum, güvenli işlemcik (thread safe) olarak ifade edilir.

Kullanım Alanları

İşlemcikler yanlış kullanıldığında bazı tehlikelere yol açmasına rağmen, bugün neredeyse bütün sistemlerde çok kanallılık, yüksek düzeyde performans sağlamak amacıyla yaygın olarak kullanılmaktadır. Örneğin büyük çapta, çok fazla istemciye hizmet veren bir haberleşme ağı kurduk, sonuçta hepsine aynı anda cevap verebilmek için çok kanallılıktan yararlanmak zorundayız; aksi halde, istemciler, sistemimizden geç haber alma ya da hiç alamama durumunda kalabilirler. Bunun dışında hepimiz çok oyunculu (multiplayer) oyunlar oynamışızdır. Eğer oyunlarda çok kanallılık kullanılmasaydı, aynı anda hem oyunumuzu oynamamız, hem de diğer oyuncularla bağlantımızı sürdürebilmemiz mümkün olmazdı. Çok kanallılık ayrıca GUI (Graphical user interface, grafiksel kullanıcı arayüzü)‘lerde de kullanılmaktadır. Mesela bir butona bastığımızda, arka planda bilmediğimiz birçok işlem gerçekleşir. Eğer yine çok kanallılık kullanmamış olsaydık butona bastığımızda GUI donup kalır, bilgisayar başında öylece kalırdık :)

Hangi Programlama Dilleri Destekliyor

Amerikan Savunma Bakanlığı tarafından geliştirilen ADA programlama dili, yazılım geliştiricilerine, komut ve kontrol sistemlerini geliştirebilmeleri olanağı sağlamak amacıyla, çok kanallılık desteği sunacak biçimde tasarlanmıştır; ancak ADA günümüzde hava elektronigi programlamasi ve askeri programlar gibi standartlaştığı alanlar dışında yaygın olarak kullanılan bir programlama dili değildir. Popüler diller arasında, JAVA, C#, Python ve Ruby ile çok kanallı tasarımlanmış programlar oluşturmak mümkündür. Özellikle JAVA, çok kanallılık içeren uygulamalar yazmak açısından oldukça zengin bir dildir. Monitör ve durum değişkenleri (condition variables) gibi, JAVA'nın çok kanallılığı desteklemek amaçlı ve kullanıcı dostu olarak sağladığı yapılar vardır. JAVA’da yazılan her uygulama en az bir tane ya da daha fazla işlemcik içerir, ancak her zaman tek bir işlemcik ile işe başlarsınız: “ana işlemcik”i (main thread) ve bu işlemciğin başka işlemcikler oluşturma gibi bir özelliği vardır. C/C++, Perl ve Visual Basic gibi diller ise çok kanallılığı dilin kendi özelliği olarak desteklemezler, bu yüzden bu dillere tek izlekli (single-threaded) diller adı verilir. Ancak C ve C++ özel kütüphaneler yardımıyla çok kanallılığı destekleyen programlar yazmak mümkündür.

Uzun Sözün Kısası…

Çok kanallılık teknolojisinin ortaya çıkmasıyla birlikte, uygulamalar daha farklı, daha güçlü bir kimlik kazandılar ve kullanıcının ihtiyaçlarına daha iyi cevap verir oldular. Günümüz teknolojisinde kullandığımız hemen hemen her programda çok kanallılığın izlerini görebiliriz. Gelişen teknolojiyle birlikte, yazılım geliştiricileri çok kanallılığa daha da ihtiyaç duyacağa benziyor.

Kaynaklar