Teknoloji sektörü şu sıralar patlama yaşıyor. Eğer son bir kaç yıl içinde bir bilgisayar ya da akıllı telefon kullandıysanız bunu muthemelen farketmişsinizdir.

Sonuç olarak kodlama becerilerine yüksek ihtiyaç duyuluyor. Bu da bir şirkette programlama işleriyle ilgilenen kişilerin ödemelerinin, ortalama işlerden daha yüksek ödeme aldığını gösteriyor. Hatta teknoloji dünyasının ötesinde bir programlama dili en az bir yaşam öyküsü kadar etkileyici bir durum yaratır.

Proglamlama dilleri istihdam sektörüne göre değişiklik gösterirler.

Finansal ve kurumsal sistemler, karmaşık işlemleri gerçekleştiren ve son derece organize olan Java ve C# gibi dillere ihtiyaç duyar. Medya ve tasarım ile ilgilenenler web sayfalarını daha dinamik, çok yönlü, fonksiyonel ve az koda ihtiyaç duymalarından dolayı Ruby, PHP, JavaScript ve Objective-C gibi dillere gereksinim duyarlar.

Bizde size bu yazımızda öğrenmeniz gereken 10 proglama dilini anlatacağız.

1) Java







Java 1990'larda Sun Microsystems tarafından geliştirilen bir sınıf tabanlı nesne yönelimli proglamlama dilidir. En çok talep gören proglama dili olan Java, kurumsal yazılım, web-tabanlı içerik, oyunlar ve mobil uygulamaların yanı sıra Android işletim sistemi için de kullanılır. Java birden çok platform üzerinde çalışır. Örnek vermek gerekirse Mac OS X üzerine yazılmış bir program aynı zamanda Windows üzerindede çalıştırılabilir.


2) C Dili 

1970'lerin başında geliştirilen genel amaçlı, zorunlu programlama dilidir. C en eski ve en yaygın olarak kullanılan bir dildir. C dili C#, Java, JavaScript ve Pyton gibi diğer popüler dillerin yapı taşlarını oluşturmuştur. C dili çoğunlukla işletim sistemleri ve gömülü uygulamaları gerçekleştirmek için kullanılır. Çünkü diğer diller için temel oluşturur. Diğer dilleri öğrenmeden önce ilk olarak C ya da C++ öğrenilmesi tavsiye edilir.


3) C++ 







C++ ilk başlarda C dilini geliştirmek için tasarlanmış, nesne yönelimli ve orta düzey bir programlama dilidir. Firefox, Winamp ve Adobe gibi bir çok büyük yazılım C++  tarafından geliştirilmişt. C++ sistem yazılımlarını, uygulama yazılımlarını, yüksek performans veren sunucuları ve video oyunlarını geliştirmek için de kullanılır.


4) C# 







NET girişiminin bir parçası olarak Microsoft tarafından geliştirilen çoklu paradigma dilidir. "C-Sharp" olarak telafuz edilir. C ve C++ ilkelerini birleştiren C#, Microsoft ve Windows platformları için yazılım geliştirmek için kullanılan genel amaçlı bir dildir.


5) Objective-C 

Objective-C, Apple şirketine ait tüm cihazların işletim sistemlerinde kullanılan nesne yönelimli, genel amaçlı programlama dilidir. API'nın yanı sıra Apple'ın OS X ve iOS işletim sistemlerine güç veren Objective-C dili, iPhone telefonlar için uygulama oluşturmak içinde kullanılır.



6) PHP 







PHP (Hypertext Processor), dinamik web siteleri ve uygulama geliştirmek için tasarlanmış sunucu tarafından komut dosyası alan ücretsiz bir programlama dilidir. Bu doğrudan harici bir dosya olabileceği gibi HTML belgesi içinede gömülmüş olabilmesi, PHP dilini web geliştiricileri için popüler hale gelmesini sağlamıştır. PHP dili Facebok, Digg ve Wordpress başta olmak üzere 200 milyondan fazla siteye hayat verir.


7) Python

Python web siteleri ve mobil uygulamalar için tasarlanmış yüksek seviyeli bir dildir. Okunabilirliği ve kompakt sözdizimi anlaşılabilir olduğundan yeni başlayanlar için oldukça kolay bir dil olarak kabul edilir. Yani geliştiriciler bir kavramı yazarken diğer dillerde olduğundan daha az kod kullanır. NASA, Google ve Yahoo tarafından kullanılır.


8) Ruby







Web siteleri yaratmak ve mobil uygulama geliştirmek için tasarlanmış olan Ruby programlama dili,  dinamik ve nesne yönelimli olmakla birlikte, basit ve yazması kolay olan bir programlama dilidir. Python gibi Ruby de yeni başlayanlar için önerilen kullanıcı dostu bir dildir.


9) JavaScript

JavaScript bir istemcidir. Netscape tarafından geliştirilmiş C'nin söz diziminden türeyen sunucu yönelimli betik bir dildir. Birden çok web tarayıcısı üzerinde kullanılabilir. İnteraktif veya animasyonlu web işlevlerini geliştirmek için gerekli olan dildir. Ayrıca oyun geliştirme ve masaüstü uygulamalarında da kullanılmaktadır. JavaScript sözleri Google'ın Chrome uzantıları, Apple'ın Safari uzantıları, Adobe Acrobat ve Reader içine gömülüdür.


10) SQL








SQL ilişkisel veritabanı yönetim sistemleri ve verileri yönetmek için tasarlanmış özel amaçlı bir dildir. Çoğunlukla "Query"(Sorgu) fonksiyonu veritabanlarındaki bilgileri aramak için kullanılır. SQL Amerikan Ulusal Standartlar Enstitüsü(ANSI) ve Uluslararası Standardizasyon Örgütü(ISO) tarafından 1980'lerde standardize edilmiştir.

Mashable
Yazının çevirisi BLOGKAFEM.NET için, Ahmet Umut Şerefoğlu tarafından yapılmıştır. 


Yazının devamını oku
Her prosese, merkezi işlem biriminde (cpu'da) işlem görmesi için belli bir süre verilir. Bu süreye quantum süresi denir. Quantum süresi içerisinde proses, merkezi işlem birimini (cpu) kullanır. Bu süre içerisinde işi bitmez ise tekrar sıraya geçer, işi biterse ise o proses sonlanır.

Her bir proses belli bir süre işlem görüp eğer işi bitmemiş ise, tekrar sıraya girer demiştik. İşte bu sebepten dolayı Round-Robin sıralaması kesintili bir sıralamadır. Çünkü bir proses işi bitene kadar işlemciyi (cpu) kullanmıyor. Belli bir süre kullanıp işlemi kesintiye uğruyor, daha sonrasında tekrar işlemciye geliyor ve işi bitene kadar bu döngü devam ediyor.


Round-Robin sıralamasının anlaşılması açısından basit bir örnek yapalım :

P1, P2, P3 adında 3 proses olsun. Bu proseslerden;

P1 prosesinin işini bitirebilmesi için CPU'yu 3 milisaniye kullanması gerektiğini varsayalım.
P2 prosesinin işini bitirebilmesi için CPU'yu 4 milisaniye kullanması gerektiğini varsayalım.
P3 prosesinin işini bitirebilmesi için CPU'yu 2 milisaniye kullanması gerektiğini varsayalım.

Quantum zaman dilimi : 1 milisaniye olsun. Bu değeri ben kendim belirledim.Yani her bir proses işlemcide 1 milisaniye işlem görecek demektir.

Bu konuyu daha iyi anlatabilmem adına, verceğim örnek için işlem görme öncelikleri önemsiz olsun. Önce P1, sonra P2'nin, sonra P3'ün sırada beklediğini düşünelim.

Evet, işlemlerimize başlıyoruz.

1. Adım :
P1 CPU'ya geldi. Quantum 1 olduğu için, 1 milisaniye işlem gördü. Geriye 2 milisaniyesi kaldığı için tekrar sıraya geçer. Daha sonra sırada bekleyen P2 CPU'ya gelir. Quantum 1 olduğu için, 1 milisaniye işlem görür ve 3 milisaniyesi kaldığı için tekrar sıraya geçer. Sonrasında ise P3 CPU'ya gelir. Quantum 1 olduğu için, 1 milisaniye işlem görür ve 1 milisaniyesi daha kaldığı için tekrar sıraya geçer.

İşlerini bitirebilmeleri için kalan işlem görme süreleri :
P1 için 2 milisaniye.
P2 için 3 milisaniye.
P3 için 1 milisaniye.


2. Adım :
Sıra tekrar P1 CPU'ya geldi. 1 milisaniye işlem gördü. Geriye 1 milisaniyesi daha kaldığı için tekrar sıraya geçer. Daha sonra sırada bekleyen P2 CPU'ya gelir. 1 milisaniye işlem görür ve 2 milisaniyesi kaldığı için tekrar sıraya geçer. Sonrasında ise P3 CPU'ya gelir. 1 milisaniye işlem görür ve 0 milisaniyesi kalır. Bu da demek oluyor ki P3 prosesi işini bitirmiştir. Çünkü görmesi gereken 2 milisaniyelik işlemi görmüştür artık.

İşlerini bitirebilmeleri için kalan işlem görme süreleri :
P1 için 1 milisaniye.
P2 için 2 milisaniye.
P3 için 0 milisaniye. İşini bitirmiştir. Sonlanır.


3. Adım
P1 CPU'ya geldi. Quantum 1 olduğu için, 1 milisaniye işlem gördü. Geriye 0 milisaniyesi kaldığı için işi bitmiştir artık ve sonlanır. Daha sonra sırada bekleyen P2 CPU'ya gelir. Quantum 1 olduğu için, 1 milisaniye işlem görür ve 2 milisaniyesi kaldığı için tekrar sıraya geçer. P3 bir önceki adımda sonlanmıştı diye işlem görmez. Bu adımda P1 prosesi de sonlandığı için, bir sonraki adımda P2 prosesi işlem görüp, sonlanacaktır.

İşlerini bitirebilmeleri için kalan işlem görme süreleri :
P1 için 0 milisaniye. İşini bitirmiştir. Sonlanır.
P2 için 1 milisaniye.
P3 bir önceki adımda sonlanmıştı.

4. Adım
P1 CPU'ya geldi. Quantum 1 olduğu için, 1 milisaniye işlem gördü. Geriye 0 milisaniyesi kaldığı için işi bitmiştir artık ve sonlanır.

Tüm prosesler böylece işlerini bitirmiş olurlar.

Quantum 1 milisaniye olduğu için her adımda, her bir prosesin işlem görme süresini 1 azalttık çünkü; mantık olarak herbiri 1er saniye işlem görüp tekrar sıraya geçiyorlar. Taa ki işleri bitene kadar. Quantım 2 olsaydı eğer, herbiri 2 şer milisaniye işlem göreceğinden, işlem görme sürelerini de 2şer 2şer azaltacaktık.


Round Robin Sıralamasının Dezavantajı
Kesintili bir sıralama olmasından dolayı kısa süre içerisinde merkezi işlem birimi sürekli olarak farklı bir prosesi işliyor. Bu da her defasında bağlam değiştirme yapması anlamına geliyor. Daha önceki yazılarımda da belirttiği gibi, işlemcinin çok fazla bağlam değiştirme yapması olayı işletim sistemi için zaman açısından maliyetlidir.


Son olarak ufak bir.... NOT : Ben konuda örnek daha kolay anlaşılsın diye Quantum sayısına 1 milisaniye dedim. Oysaki gerçek şartlarda bir bilgisayar, 1 milisaniyede milyonlarca proses işlemi gerçekleştirebilir. Yani işletim sistemlerinde belirlenen o quantum sayısı 1 milisaniyeden çok çok daha küçük bir değerdir aslında.

Konuyla ilgili aklınıza takılan yerleri, görüşlerinizi veya düşüncelerinizi aşağıdaki yorum formu aracılığıyla bana iletebilirsiniz. Aklınıza takılan yerler var ise, size elimden geldiğince yardımcı olmaya çalışırım.
Yazının devamını oku
FIFO'nun açılımı Firt İn First Out ifadesidir. Türkçe'de ise bu ifade "İlk Giren İlk Çıkar" anlamına gelmektedir. FIFO sıralaması, bilgisayarımızın merkezi işlem birimi olan CPU'da işlem görmek isteyen proseslerden, bekleme kuyruğuna ilk önce gelen prosesin öncelikli olarak işlem görmesi mantığına göre çalışır.

FIFO sıralaması kesintisiz bir sıralamadır. Yani CPU'ya gelen bir prosesin işi bitmeden başka bir proses işlem göremez anlamına gelmektedir.


FIFO sıralamasını bir bankanın kuyruğuna benzetebilirsiniz. Kuyruğa ilk önce gelen müşteri, işlem görür ve işi bitene kadar da kuyruktan ayrılmaz. İlk gelenin işi bitip gittikten sonrasında ise, bir sonraki bekleyene sıra gelir. FIFO sıralaması da aynen bu mantıkla çalışan bir sıralamadır.

FIFO Sıralamasının Dezavantajı
Her prosesin işlem göreceği süre farklıdır. Bu sebeple prosesler arası boş ve gereksiz beklemeler çok olur.

Örneğin en öndeki A prosesinin işini bitirmesi için 10 saniye işlem görmesi gerektiğini düşünüelim. Oysaki arkadaki B prosesi 1 saniye işlem görse işini bitirecektir ama; FIFO mantığına göre ilk önce A prosesi işlem görmesi gerektiği için, B prosesi boş yere 10 saniye bekleyecektir. Bu işletim sisteminin hızlı çalışma prensibi açısından olumsuz bir durum oluşturur. Bu sebeple işletim sistemlerinde FIFO yöntemi tek başına tercih edilmez ve diğer yöntemler ile beraber kullanılır. Örneğin, farklı bir öncelik gerekçesi gerektiren bir yötemde, aynı önceliğe sahip proseslerin kendi aralarında sıralanması için kullanılabilir.

Yazının devamını oku
Daha önceki yazılarda bir prosesi ancak başka bir proses yaratabilir dedik ve bir prosesin fork() çağrısıyla başka bir prosesi yaratması sonucu bir program için birden çok proses paralel olarak çalışabilir dedik fakat; proses oluşturmak işletim sistemi için bazı sebeplerden dolayı çok maliyetli bir iştir. Bu sebeple bir programın birden çok işlem yapması gerekiyorsa eğer birden fazla proses üretmesi yerine Thread yani iplik kullanımının işletim sistemi açısından daha avantajlı olduğunu söylemiştik. Buraya kadar yazdığım ve belirttiğim herşeyin sebeplerini öğrenecez bu yazıda.

Bir program çalışırken ana prosesin yeni bir proses yaratması yerine bir iplik yaratması neden daha avantajlı. İplikler de prosesler gibi çalışırlar fakat hafif proseslerdir dedik. İplikler de prosesler gibi çalışıyorlarsa iplikler ile prosesler arasında farklar nelerdir? Bunlara değineceğiz.

İpliklerin Özellikleri ve Proses'ten Farkları

  • Thread'ler, proses içinde bulunurlar ve aynı adres uzayını paylaşırlar. Bir proses içerisinde birden fazla iş yürütebilirler.
  • İplikler prosesler gibi birbirlerinden bağımsız değildirler. Kendi aralarında kaynakları ve bazı verileri birbirleriyle paylaşırlar. 

Bakınız :

Yani kısacası; 
İşler birbirinden tamamen bağımsız ise : PROSES
İşler birbirine bağlı ve birlikte yürütülüyorsa : THREAD (İplik)  diyebiliriz.


İpliklerin Prosesler İle Olan Ortak Özellikleri:

  • Paralel çalışabilirleri etkileşebilirler ve haberleşebilirler.
  • Dış dünya ile haberleşebilirler.
  • Ardışıl işlemler yapılabilir.
  • İplikler de prosesler gibi bağlam(durum) değiştirebilirler. Hazır, Askıda, Çalışıyor durumlarda olabilirler.


İpliklerin Proseslere Göre Avantajları

  • Tek bir proses bile birden fazla işlem yapabilir. Böylece işlemcide daha az bağlam değiştirme olayı gerçekleşir. Sırada olan daha az proses olur ve bilgisayar işlemleri daha çabuk gerçekleştirebilir. Her işlemde proses kontrol bloğu yeniden güncellenmez. İşletim sistemi işlemleri gerçekleştirirken zaman kaybı yaşamaz.
  • Çok işlemcili sistemlerde faydalıdır. İpliklerin bazıları işlemciye yönelik işlemler yaparken bazıları giriş -çıkış işlemleri yapıyorsa yapılan iş için daha iyi performans elde edilir.
  • Proseslerin kaynakları vardır. İşletim sisteminde yer işgal ederler. Ne kadar çok proses olursa RAM'de o kadar çok yer işgal edilir. İpliklerin ise kaynakları yoktur. Mevcut prosesin sahip olduğu kaynağı kullanılar. Fazladan yer işgal etmezler. Yaratılmaları ve yok edilmeleri proseslere göre daha kolaydır.

Daha önceki yazımda şunu demiştim;
Bir programı birden çok prosesin çalıştırmasının avantajları ve dezavantajları vardır. Avantajı; bir programın çalışması için birden çok proses çalıştığı için o program kısa sürede işleme girebilir. Yani bir binayı birden çok işçinin inşa etmesi gibi fakat; bunun şöyle bir dezavantajı var. Ne kadar çok proses olursa, bilgisayarın RAM'inde o kadar yer işgal edilecektir ve CPU bir program için birden fazla proses işleyeceği için bu bilgisayarı daha çok yoracaktır. Kısacası bellek tahsisi, bağlam değiştirme veya anahtarlanma işlemleri sırasında yüklenmeleri işletim sistemi açısından daha maliyetli olur.

İplik denen olay işte tam da burada devreye giriyor. Yani tam olarak demek istediğim şey şudur. İşletim sisteminde bir iş için 3 ayrı prosesin çalışması yerine, tek bir prosesin çalışıp içinde 3 iplik bulundurması ile aynı işlemler  gerçekleştirilebilir. Proses işlemlerini işletim sistemleri CPU'da işlerken, yukarıda da saydığımız bazı sebeplerden dolayı (bağlam değiştirme olayı vs. ) maliyetli olması sebebiyle, işletim sisteminde bir iş yaparken çok fazla proses kullanmak yerine daha az proses ve daha çok iplik kullanmak, daha çok tercih edilir.

Özetle, aynı örnek üzeriden konuşacak olursam. Tek proses ve bu proses içinde 3 iplik barındırarak çalışan bir program, 3 farklı proses ile çalışan programa göre, işletim sistemi açısından çoğu zaman avantajlıdır. Bu sebeple bir işlem için çok fazla proses kullanmak yerine, tek proses kullanıp ve tek prosesin içinde iş bölümü yapacak olan birden çok iplik yaratıp kullanmak daha mantıklıdır.
Yazının devamını oku
İplikler hafif proses olarak adlandırılırlar. Prosesler gibi çalışırlar ama proseslere göre belli başlı farkları vardır. Ona da farklı bir başlık altında değineceğim. Türkçesi iplik olan bu hafif prosesler, ingilizce ifadesi olan Thread olarak da geçer bazı kitaplarda veya web sitelerinde.

İplikler, tek bir prosesin daha çok işlem yapmasına olanak tanırlar. Bilgisayar belleğinde fazladan alan işgal etmezler. Belli bir alana sahip proseslerin içinde çalışırlar. Bir proses bir ipliğe sahip olabileceği gibi birden fazla ipliğe de sahip olabilir.




İplikler kolay oluşturulup kolay yok edilirler.  Bir program yazarken, programın mevcut prosesi içinde bir iplik yaratıp birden çok işlem yapmak istiyorsanız eğer, derleyicinize;

#include <pthread.h>

kütüphanesini eklemeniz gerekiyor.

Threadler yani iplikler ile işlemler yaparken bazı ifadeleri bilmeniz gerekiyor. İplikler ile işlem yaparken bu ifadeler olmazsa olmaz ifadelerdir. Programı yazmaya başladığınız zaman main kısmında öncelikli olarak yapacağınız işlemlerdir. Kısacası bu ifadeler iplik işlemlerinin demirbaş işlemleridir.

pthread_t()

İpliklere ait bilgileri tutar. Bir ipliğin sahip olması gereken tüm özellikler bu ifade ile tanımlanmış olan ifadede saklanır.

pthread_create() :

 Bu ifade ile yeni bir iplik oluşturulur. 4 farklı parametre alır.
1. parametresi : İpliğe ait bilgileri tutan değişkenin adresini tutar.
2. parametresi : İpliğin özelliklerini tutar. Yapacağımız örneklerde NULL olarak kalacak.
3. parametresi : İpliğe ait olan fonksiyonun adını tutar.
4. parametresi : İpliğimize ait olan fonksiyona değer döndereceksek eğer, 4. parametre kısmı kullanılır. Bu parametre için unutmamanız gereken en önemli özellik ise, bu parametre sadece void değerler alır. Eğer ki farklı türdeki değerler yollayacaksanız fonksiyona, ilk önce (void *)x işlemi yaparak değerinizi void türüne dönüştürmeniz gerekiyor. Videolarda bunu daha iyi anlayacaksınız zaten.

pthread_join() 

"İpliğin işlemini bitirmesini bekle" anlamına gelir. Eğer iplik kullanarak bir program yazacaksanız bu ifade olmazsa olmaz bir ifadedir. Bu ifade sayesinde iplik işini bitirmeden proses sonlanmaz. Bu ifade 2 parametre alır.

1. paremetresi : İpliğe ait bilgileri tutan değişkenin kendisini tutar.
2. parametresi : Geri dönüş değerlerini tutar. Eğer ipliğinizin geri dönüş değeri var ise, ikinci parametre bu veriyi tutar. Yarattığınız thread geriye değer döndermiyor ise eğer, bu parametreye NULL yazılır.

pthread_exit()

İçine void değerler alır. İpliğin geri dönüş değerini tutarlar. Geri dönüş değeri yok ise içine NULL yazılır.


İplikler nedir, nasıl çalışırlar, iplik oluşturup çeşitli işlemler nasıl yapılır? Bütün bunları daha iyi anlamanız açısından iplikler ile ilgili 4 tane örnek video çektim.

1. Örnek : Bu örnek basit bir thread örneğidir. İpliklere değer gönderme falan yok. Basit olarak threadlerin genel yapısını görmenizi sağlayacak bir örnektir. Örnekte her fonksiyonu bir iplik olarak düşüneceğiz.


2. Örnek :  Bu örneğin bir öncekinden farkı, bu sefer ipliğimize değer gönderiyoruz. Yine önceki örnekte olduğu gibi her fonksiyonu bir thread olarak düşünecez.


3. Örnek : Artık örneklerimizin gelişmişlik düzeyi giderek artıyor. Bu videoda Thread'lerin değer döndermesini göreceğiz. pthread_join() ifadesinin nasıl kullanıldığını göreceksiniz. Her fonksiyon bir thread olarak düşünülecek.


4. Örnek : Diğer 3 örneğe göre en gelişmiş olan örnektir. Bu örnekte bir yapı kullanacağız. Kullanacağımız bu yapı sayesinde bir Thread'e (ipliğe) birden çok veri gönderebileceğiz ve oluşturacağımız her iki Thread, tek bir fonksiyonu kullanacaktır. Üstelik de ipliğimiz değer dönderen bir iplik olacaktır.

Yazının devamını oku

Oluşturduğumuz prosesler veya mevcut proseslere, bazı sistem çağrıları ile istediğimiz yaptırabiliyoruz. Bugün ise başlıktan da anlayacağınız üzere "Bir Prosesi Öldürme, Bekletme, Uykuya Alma ve Yeniden Başlatma" çağrılarını tanıtacağım kısaca.

Kodlar, kütüphaneler C dili kütüphaneleridir. Çağrıları ise Linux işletim sistemine ait sistem çağrılarıdır.

Bekleme ve Sonlanma Çağrıları

Bu çağrıları kullanabilmek için derleyicimize,

#include <sys/types.h>
#include <sys/wait.h>

kütüphanelerini eklememiz gerekiyor.

Sleep() Çağrısı

Herhangi prosesi, parantezler içerisine yazacağımız saniye kadar bekletebiliriz. Hangi prosesi bekleteceğiniz ise tamamen size kalmış. Mesela çocuk proses aktif olacağı sırada ben program koduma sleep(1) yazdım diyelim. Bu durumda çocuk prosese sıra geldiği zaman çocuk proses çalışmayacak. 1 saniye bekleyecek. Bu sırada başka proseslerin işleri varsa onlar işlerini yaparlar ve 1 saniye sonra çocuk proses yeniden aktif olur. Yani sleep(1) yaparak istediğimiz herhangi bir prosesi 1 saniyeliğine uyutmuş oluruz. Eğer ki sleep(5) yazarasak, o anda aktif olan proses 5 saniyeliğine uyku moduna geçer ve bu süre dolana kadar da aktif olmaz. Süre dolduktan sonra tekrar kendiliğinden uyanır ve işlemlerine devam eder. Bilgisayardaki işlemler milisaliseler içerisinde gerçekleştiği için 1 bile saniye aslında önemli bir zaman aralığıdır.


Wait() ve Waitpid() Çağrıları

Bu ifadeyi aktif olan proses içine yazdığımız zaman o proses, herhangi bir alt prosesin işlemini bitirmesi için bekler. Sonlanmadığı için programı da sonlandırmaz. Yani proses vardır ama işlem yapmıyordur diyebiliriz. Diğer prosesin işini yapmasını bekler. İpliklerde pthread_join() ifadesi bu görevi görüyordu. Proseslerde ise wait() ve waitpid() çağrıları bu görevi yapar.

wait(int *durum) şeklinde tek bir parametre alır içine. Bu parametre adres tutar. Beklenen proses sonlandığında, sonlanan bu prosesin çıkış değerini tutar. wait() çağrısı, waitpid() çağrısının eski versiyonudur.

Waitpid(pid_t pid, int *durum, int secenekler); şeklinde 3 parametre alır.
Birinci parametreye bekletmek istediğimiz prosesin ID numarasını yazıyoruz.

1. parametre : Hangi prosesi bekleyeceksek onun ID'sini yazıyoruz. Herhangi bir çocuk proses beklenecekse ilk parametreye "-1" değeri girilir.
2. parametre : Bu parametre adres tutar. Beklenen proses sonlandığında int *durum olarak belirttiğimiz ikinci parametre ifadesi, sonlanan bu prosesin çıkış değerini tutar.
3. paramtere : Özellikler parametresidir. "0" veya bazı özel değerler alır. Sıfır yazmadığımız durumlarda alabileceği bu bazı özel değerlerin 3 tanesine bakalım :

WNOHANG     : Hiçbir çocuk proses sonlanmıyorsa hemen geri dönmeyi belirtir.
WUNTRACED : Çocuk proses durdurulduğunda geri dönülecektir.
WCONTINUED:Durdurulan çocuk proses SIGCONT sinyali aldığında geri döner.



SİNYAL ÇAĞRILARI


Buraya kadar yazdıklarım Bekleme ve Sonlanma Çağrıları'ydı. Şimdi ise proseslerdeki bazı sinyal alma çağrılarına bakalım.

Sinyal çağrıları içi kullanılması gereken kütüphane;
#include <signal.h>

Sinyal çağrılarından sadece kill() ifadesine değineceğim için en başından şunu belirtmeliyim ki bu çağrı;

kill(pid_t pid, int signal);

olmak üzere 2 parametre alır. İlk parametre proses ait bilgileri tutar. İkinci parametre ise sinyal bilgisini tutar. O proses ne yaptırmak istiyorsak, signal kısmına o sinyalin adını yazmamız gerekiyor. Alttaki ifadelerden de ne demek istediğimi daha iyi anlayacaksınız.

pid_t prosesID; //olsun.
prosesID = fork(); //çocuk prosesin bilgileri artık "prosesID" ifadesi içinde saklanıyor.

Artık "prosesID" ifadesini kullanarak, çocuk prosese kill() aracılığıyla istediğimiz sinyali uygulayabiliriz.

kill(prosesID,SIGSTOP) ve kill(prosesID,SIGCONT) Çağrıları

Bu ifadeler sayesinde, ID numarasını bildiğimiz bir prosesin işlemini istediğimiz zaman sonlandırıp, istediğimiz zaman yeniden aktif edebiliyoruz. Mesela şöyle bir örnek vereyim. Çocuk prosesin ID numarasının "prosesID" olduğunu varsayalım. Ben kill(prosesID,SIGSTOP) ifadesini kullanırsam eğer, çocuk proses duracaktır ve hiçbir iş yapamayacaktır. Taa ki biz yeniden kendisini aktif edene kadar. kill(f,SIGCONT) ifadesi ise işte burada devreye giriyor. SIGSTOP komutu ile işlem yapmasını durdurduğumuz bir prosesi SIGCONT komutu ile istediğimiz zaman yeniden aktif hale yani iş yapabilir hale getirebiliyoruz.



kill(prosesID,SIGKILL) Çağrısı

Bu ifade ile ID numarasını bildiğimiz bir prosesi istediğimiz zaman öldürebiliyoruz. Öldürdüğümüz proses bir daha işlem yapamaz ve eğer ana proses ile programın sonlanmasına sebep olur. Öldürmek istediğimiz ana prosesin ID numarasının "prosesID" olduğunu varsayalım. Bu durumda kill(f,SIGKILL) olarak kullanılır bu ifade.


Derlediğiniz programda ID numarası yazılması gereken kısım olan "prosesID" kısmında "getpid()" ifadesini kullanabilirsiniz.
  • kill(getpid(),SIGSTOP)
  • kill(getpid(),SIGCONT)
  • kill(getpid(),SIGKILL)
vs. gibi.


Bu konuyla ilgili anlatacaklarım bu kadar. Konuyla ilgili aklınıza takılan tüm soru, öneri, ve isteklerinizi aşağıdaki yorum formundan belirtebilirsiniz.
Yazının devamını oku
Proses konusunun devamı olan Fork() sistem çağrısından bahsedeceğim. Eğer daha önceki yazımı okumadıysanız ilk önce buraya tıklayarak o yazımı okumanızı tavsiye ederim.

Daha önceki yazımı okuduysanız orada bahsetmiştim. Bir program bir yada birden fazla proses tarafından çalıştırılabilir. Bir programın birden fazla proses tarafından çalıştırılması demek, tek bir prosesin yapacağı işi, birden fazla proses yaparak o programın daha kısa sürede ve daha hızlı bir şekilde çalışmasına yardımcı olduğundan bahsetmiştik. Yani bir binayı bir işçi yerine birden çok işçinin inşa etmesi nasıl ki o inşaat işinin daha kısa sürede tamamlanmasını sağlıyorsa, bunu da ona benzetebilirsiniz. Çünkü aynı anda birbirine paralel olan işler yürütülebilmektedir. Anne proses bir iş ile ilgilenirken çocuk proses aynı zamanda daha başka bir iş ile ilginiyor olabilir veya aynı işi yapıyor olabilirler yada bir diğerini bekliyor da olabilirler. Birebir aynı olduğu gibi farklı bir proses de olabilir. Biz bunu kullanacağım sistem çağrıları ile ayarlayabiliyoruz.

Fork() Çağrısı Nedir?

Bir programın çalışmasına yarayan bir prosesin kopyasının oluşturulması işlemidir. Yani kısacası yeni bir proses oluşturma işlemidir. Oluşan bu kopya prosese çocuk proses denir. Bu çocuk proses kimden kopyalandıysa, kopyalandığı o proseses ise Anne prosestir. Bu sistem çağrısı ile oluşan ikinci kopya prosesin yani çocuk prosesin tüm özellikleri, kod belleği birebir anne proses ile aynıdır.




Program koduna yazdığımız fork() ifadesinden sonra hem anne proses hem de çocuk proses aynı işlemi yapar.

Örneğin ben derleyiciye printf("Merhaba Dünya\n"); yazdırdım. Eğer ben bu tırnak içerisindeki kelimeyi fork() çağrısından sonra yazarsam, 2 defa "Merhaba Dünya" yazılır ekrana. Çünkü yazma işlemini hem çocuk proses yapıyor hem de anne proses yapıyor. Kullanacağımız sistem çağrıları yardımıyla çocuk prosese başka işler yaptıra da biliriz.

Aynı program içerisinde aynı işi yapan bu 2 prosesin herbirine farklı işler yaptırmak için hangi prosesin çocuk, hangi prosesin ise anne proses olduğunu bilmemiz gerekiyor. Bunu da anlamak için, proseslerin dönüş değerini bilmemiz yeterlidir. fork() dediğimiz çağrı ile çocuk proses "0" değeri atanır. Anne prosese ise "0" dan farklı bir numara atanır.

Bu aşamadan sonrası için bir video çektim. Daha iyi anlamanız açısından fork() çağrısı ve proseslerin detaylı anlatımı için bir video hazırladım.




Konu ile ilgili alıntı yaptığım ek bir bilgi : Ufak tefek işleri parent yaparken, bütün ameleliği çocuk prosese yükler. Oturup gazete okuyan bir babanın çocuğundan durmadan çay,terlik,yastık vs istemesi gibi bir şey bu. Bu olay proses'in daha hızlı işlem yapmasına olanak sağlar çünkü işleyiş iki koldan ilerler. İşleyiş olarak multithread olayına benzer ama temelde tamamen farklıdırlar.
Yazının devamını oku
Proses kelimesi ingilizcedeki process kelimesinden gelmektedir. Süreç, işlem gibi anlamlara gelmektedir. Bilgisayarımızın da merkezi işlem biriminde (CPU) çalışan işlemler yani prosesler vardır. Bu proseslerin kimisi işletim sisteminizi çalıştırmaya yararlar, kimiler ise kullandığınız diğer masaüstü programları çalıştırmaya yararlar. Tarayıcı, Media Player, ofis programları vs. gibi tüm programlar aslında birer prosestir ve kendi altında birden çok proses de bulundurabilirler.

  • Özet Bilgi : Karıştıranlar için şimdiden belirteyim. CPU, MiB ve İşlemci kelimeleri aynı şeylerdir. Bilgisayarın beynine verilen isimlerdir bunlar. Tüm veriler, programlar ve işlemler burada gerçekleşir. CPU, Central Unit Process anlamına gelir. MİB de bunun Türkçesi olan Merkezi İşlem Birimi anlamına gelir. Yazıyı okurken bu ifadeleri sık sık kullnacağım.

Bilgisayarda kullandığınız her program, bilgisayarın işlemcisindeki prosesler aracılığıyla çalışırlar. Örneğin siz müzik dinlemek için Windows Media Player'a tıklayıp açmak istediniz. Tıkladığınız sırada Windows Media Player'ın çalışmasına yarayan prosesler hemen devreye girerler ve bilgisayarın işlemcisine gelip işlem görürerler. Bilgisayar'da Media Player'ı açar. Bilgisayarlar o kadar hızlı çalışırlar ki bu işlemler milisaniyeler içinde meydana gelir.

Şimdide proseslere biraz daha somut olarak bakalım. Ctrl+Alt+Delete yapın ve görev yöneticisini açın. Üstteki sekmelerden "İşlemler" yazan kısma gelin. Bu kısımda gördükleriniz proseslerdir.


 
Alt kısımdaki "işlemler" yazan kısma dikkat edin. Benim bilgisayarımda şuanda aktif olarak çalışan 74 proses varmış.

Proses listesi açık iken masaüstünüzden herhangi bir program açıp kapatın. Açtığınız zaman o programa ait proses yada prosesler orada gözükeceketir. Kapattığınız zaman kaybolacaklardır. Bazı programlar için tek bir proses görülebilirken bazı programlar birden çok proses tarafından çalıştırılırlar. Örneğin yukarıdaki ekran görüntüsünde Google Chrome'un 4 farklı proses tarafından çalıştığını görebilirsiniz. Biraz daha alt kısımda yer alan Firefox'un tek bir proses tarafındna çalıştığını görebiliriz. Fakat sadece buna bakarak hangi programın daha iyi olduğuna karar vermeyiniz. Belkide içlerinde bulunan iplik sayıları farklıdır. İplik konusuna daha sonraki yazılarımda değineceğim.

Bir programı birden çok prosesin çalıştırmasının avantajları ve dezavantajları vardır. Avantajı; bir programın çalışması için birden çok proses çalıştığı için o program kısa sürede işleme girebilir. Yani bir binayı birden çok işçinin inşa etmesi gibi fakat; bunun şöyle bir dezavantajı var. Ne kadar çok proses olursa, bilgisayarın RAM'inde o kadar yer işgal edilecektir ve CPU bir program için birden fazla proses işleyeceği için bu bilgisayarı daha çok yoracaktır.

Şimdi proses durumlarını anlatayım. Neden işlemciyi daha çok yorduğunu ve ne demek Proseslerin Durum (Bağlam) Değiştirmesi kısmında daha iyi anlayacaksınız.

Proses Durumları

Prosesler hazır, bekleme ve çalışma durumlarında bulunabilirler.


Çalışma Durumu : Prosesin CPU'da işlem gördüğü durumdur.
Hazır Durumu     : Prosesin hazır olduğu ve çalışmak için (CPU'dan işlem görmek için) sırasının gelmesini beklediği durumdur.
Askıda Durumu   : Prosesin hazır duruma geçmek için bir olayın gerçekleşmesini beklediği durumdur.

Örneğin; hesap makinası programını açtınız. Açtığınız anda onu çalıştıran proses önce hazır kuyruğuna geçer, sonra işlemcide işlem görerek çalışma durumuna geçer ve program açılır. Tabi bunlar çok hızlı bir biçimde, milisaliseler içerisinde gerçekleşirler.  Daha sonrasında ise hesap makinesi programını çalıştıran proses, "Askıda Durumu"na geçer. Sizden rakam bekler. Siz rakam girip bir işlem yapmadığınız sürece o hep askıda kalır. Daha doğrusu askıda kuyruğuna geçer. Çünkü birden fazla proses askıda bekliyor olabilir. Bu sırada işlemcide başka bir program işlem görüyordur. Siz rakam girdiniz diyelim veya direkt olarak 3 + 2 yazdınız diyelim. (Tek tek uzun uzun anlatmamak için direkt olarak 3+2 dedim. Normalde 3 ve + ve 2 ayrı ayrı işlemlerdir.)
Program bu süre içerisinde yukarıda yazdığım işlemleri tekrar eder. Askıdan çıkar --> Hazır Kuyruğuna geçer --> Çalışır durumuna geçer. Çalışır durumunda size bir şey yansımaz ama o girdiğiniz ifadeleri bilgisayar kendi beyni olan CPU'da işler ve tekrar askıya geçer. Sizden tekrar bir işlem bekler. Askıda olduğu sürece işlem yapmaz. Siz eşittir yaptığınız sırada işlemler tekrar eder. Askıdan Kuyruğundan çıkar  --> Hazır Kuyruğuna geçer --> Hazır Kuyruğundan çıkıp --> Çalışır duruma geçer ve ekrana 5 sonucunu yazar.

Neden Hazır Kuyruğu veya Askıda Kuyruğu diyorum? Çünkü bilgisayarda birden çok proses vardır ve herbir proses işlemcide tek tek işlem görür. Yani uzun bir bilet kuyruğu düşünün. 1 tane gişe olduğunu düşünün. Gişe, işlemcidir. Kuyrukta hazır bekleyen insanlar ise birer proses olarak düşünülebilir. Tabi bu proseslerin kimisi askıda kuyruğundadır kimisi ise hazır kuyruğunda bekliyor olabilir. Kimisi ise işlem görüyordur.

Her Proses Kendi İle İlgili Olan Kuyruğa Girer!

Bu kısım önemli. Tüm programlar Merkezi İşlem Birimi'nde (MiB)'de yani CPU'da işlem görmeden önce, henüz askıda durumundayken, herhangi bir kuyruğa girmez. Kendi ile ilgili olan kuyruğa girer. Çünkü bazı programların çalışması daha uzun sürebilir bazı programların çalışması daha kısa sürebilir. Tüm prosesler aynı kuyruğa girerse, açılması daha kısa süren program, açılması daha geç olan programında arkasında sıraya girer ise, 1 saniyede açılacak olan program 10 saniyede açılabilir. İşletim sitemi geliştiriciler de bunun önüne geçebilmek için, benzer işlemleri yapan programları bilgisayar RAM'inde farklı farklı yerlerde kuyruğa girmesini sağlamışlardır.

Bakınız :



Bir Proses Neden Sürekli Çalışmayıp Askıda ve Bekleme Konumlarına Geçiyor?

Bilgisayarda hesap makinesi dışında onlarca çalışan program olduğunu Ctrl+Alt+Delelete yaparak  görmüştük. Her proses merkezi işlemci birimi olan CPU'yu yani bilgisayarın beynini işgal ederse ise sürekli, bilgisayar kitlenir. Bu sebeple işi biten proses işlemcide işlem gördükten sonra çıkmak zorundadır. Eğer proses tekrardan işlem görmek istiyorsan tekrardan hazır kuyruğuna geçer.


Prosesin Durum (Bağlam) Değiştirme Olayı

Proses Durum Değiştirirken Hangi İşlemler Gerçekleşir? Şimdi buna değinelim

Prosesler, içlerinde bir takım bilgiler barındırırlar.  Bu bilgiler Proses Kontrol Bloğu denen yerde tutulur. Bu proses kontrol bloğunda ise, şu bilgiler bulunur :



Proeses durum değiştirir iken... Yani; Hazır - Beklemede - Askıda durumları arası geçiş yaparken yukarıda sayılan PCB (proses kontrol bloğu) güncellenir. Tüm bu bilgilerin her durum değiştirme sırasında tekrardan güncellenmesi ise, işletim sistemi için zaman kaybıdır. PCB haricinde, durum değiştirme olayı sırasında proseslerde şu işlemler gerçekleşir :



Gördüğünüz gibi birden çok proses bir programı çalıştırırken o program için çalışma kolaylığı sağladığı gibi, dezavantaj olarak boş yere bilgisayar hafızasında yer kaplar ve işlemci daha çok işlem yapmak zorunda kalır. Bu da işlemcinin sırada bekleyen diğer işlemleri gerçekleştirmesi normalden daha uzun sürer.

FORK() Sistem Çağrısı

Bu çağrı yeni bir proses oluşturma çağrısıdır. Çalışan bir programa hizmet eden bir proses yerine birden çok prosesin hizmet etmesini sağlayabiliriz. Bu prosesler birnine paralel olarak çalışır. Örneğin çocuk proses başka bir prosesi çalıştırıp ona başka işlemler yaptırırken anne proses de kendi kendine başka işlemler yapabilir. Fork() olayı sayesinde oluşturacağımız proses ile aynı anda birbine paralel olarak çalışan birden çok işlem yapabiliyoruz. Fork sistem çağrısına bir sonaki yazımda ayrıntılı olarak değineceğim.

Konu ile ilgili aklınıza takılan tüm soruları aşağı kısma yorum olarak yazabilirsiniz. Size elimden geldiğince yardımcı olmaya çalışırım.
Yazının devamını oku
Daha önceki yazımda yazdığım pointer konusunun mantığını anladıysanız bunu anlamanız zor olmayacaktır. Tanımladığımız bir dizi içerisinde pointerları kullanarak gezebiliriz.

Örnek bizi dizi tanımlayalım.

int dizi[5] = {3,5,8,9,7};

Dizilerin mantığından da anlayacağınız üzere dizi içerisindeki her bir elemanın bir adresi bir de indisi vardır. İndis ve adres farklı şeylerdir. Mesela üstteki 5 elemanlı diziyi ele alalım.

0. indisteki eleman = 3 
1. indisteki eleman = 5
2. indisteki eleman = 8
3. indisteki eleman = 9
4. indisteki eleman = 7
 
(Bildiğiniz üzere dizi elemanları sıfırıncı indisten başlar.)

Bu değerler arasından 1. indisli 5 sayısını ele alacak olursak 5 değerinin bulunduğu indis 1'dir ama adresi 0x7ffd084 gibisinden karmaşık bir ifadedir.

Bildiğiniz gibi işaretçiler(pointer) adresler üzerinden işlemler yapmamızı sağlayan bir kavramdır. 

int *p;
p = dizi;

yaparsak eğer, biz dizinin 1. değerinin adresini p işaretçisine atamış oluruz. Başka bir ifade ile 0. indisin adresini, p'ye atamış oluruz.


Yani biz bu aşamadan sonra;
cout << *p;

yaparsak; ekrana dizinin 1. elemanını atamış oluruz. Peki dizinin diğer elemanlarına nasıl ulaşabiliriz?


Dizi içerisindeki ifadeler bilgisayar hafızasında sıralanmış ifadelerdir. Bunlar birbirleri ile bağlantı içindedirler. Bu sebeple biz;

p++;
cout << *p;

yaparsak... Dizinin 2. elemanını ekrana yazdırmış oluruz. Burada pointerın adresini 1 arttırdık. Pointer ifadesi dizinin ilk adresini tutuyordu. Yada başka bir ifade ile dizinin 1. elemanının adresini işaret ediyordu. Biz bunu bir arttırarak p'nin artık dizinin 2. elemanının adresini işaret etmesini sağladık. Çünkü biliyoruz ki dizi içerisindeki elemanların adresleri bilgisayar hafızasında sıralıdırlar.

Bakınız ekran görüntüsü :


Ben tek tek yazdırdım ama 1. cout ifadesini ve p++ ifadesini bir for döngüsü içine atarsanız tüm elemanları kolaylıkla ekrana yazdırabilirsiniz.


Ayrıca, pointerlar ile ekrana yazdırma işini, diziler gibi şu şekilde de yapabiliriz :




Konun daha rahat kavranması açısından basit örnekler verdim. Burada verdiğim örnekler mantığın kavranmasına yönelik örneklerdir. Aklınıza takılan yerleri aşağı kısma yorum olarak yazabilirsiniz.
Yazının devamını oku
C yada C++ dillerini yeni öğreniyorsanız yada ilk defa bir programlama dili öğreniyorsanız pointer mantığını anlamakta biraz zorlanabilirsiniz. Yeni başlayanlar için kavraması biraz karmaşık olduğundan bu konuyu ele almak istedim. Bu yazıdan sonra artık pointer kavramının mantığını kolaylıkla kavrayacağınızı düşünüyorum.

Pointer dediğimiz şey bir işaretçidir ve adres tutar. Bu klasik tanımdır. Pointer olarak tanımlayacağımız ifadenin başına yıldız(*) işareti koyarak "bu ifade bir pointer ifadedir" deriz bilgisayara. Mesela;

int p;
olarak tanımladığımız bir ifadede p ifadesi integer yani sayısal değerler tutan bir ifadedir deriz. Sadece sayısal değerleri tutar. Fakat bu ifadeyi şu şekilde tanımladığımız zaman;

int *p;

bu p ifadesi için şunu demiş oluruz :  "p ifadesi bir pointer'dır. p ifadesi bir işaretçidir ve sadece adres tutar!"

Tırnak içinde belirttiğim cümleye dikkat edin. "p ifadesi" dedim. "*p" ifadesi demedim. İşte asıl karmaşıklık burada başlıyor.

*p ifadesi tanımlama ve kullanım aşamalarında farklı görevler üstlenir. Eğer ki siz herhangi bir ifadeye "bu ifade bir pointer'dır!" demek istiyorsanız tanımlama aşamasında o ifadenin başına yıldız (*) ifadesini eklersiniz.

Önce tanımlama aşamasından başlayalım anlatmaya...
Birkaç örnek vermem gerekirse,

int *a;  // "a" ifadesi bir pointer'dır ve adres tutar.
int *ptr;  // "ptr" ifadesi bir pointer'dır ve adres tutar.
int *b;  // "b" ifadesi bir pointer'dır ve adres tutar.

tanımlama aşamasında kullandığımız her yıldızlı(*) ifade bu anlamlara gelir.

Pointer olarak tanımlanmış ifadeyi kullanım aşamasında ise yıldızlı(*) ifade değer tutan bir ifade görevindedir. (Kullanım aşamasında derken, tanımlama sonrası değer atama veya ekrana yazdırma işlemleri vs.)

*a  ifadesi değerin kendisini tutar; a ifadesi ise o değerin adres bilgisini içerir.
*ptr  ifadesi değerin kendisini tutar; ptr ifadesi ise o değerin adres bilgisini içerir.
*b  ifadesi değerin kendisini tutar; b ifadesi ise o değerin adres bilgisini içerir.

Örnek : ptr ifadesinin değeri 5 ise; bu ifadenin adresi : 0x7ffd084 gibisinden, RAM bölgesindeki adresi gösterir.

Kısacası, kullanım aşamasında, pointer bir ifade var ise elimizde, bu ifadenin başında yıldız var ise değerin kendisi gösterilir, başında yıldız yok ise değerin adresini gösterir.

Yani bunun çıktısını cout ile aldığımız zaman;
*ptr ifadesi ekrana = 5 değerini gösterir.
ptr ifadesi ekrana = 0x7ffd084 değerini gösterir.

 Bakınız :


Ekran görüntüsünün açıklaması :
"p" ifadesi adres tutan bir ifade olduğu için, ona yalnızca başka bir ifadenin adresi atanabilir. Mesela üstteki ekran görüntüsüne göre p = a yapamazdık. Yani a ifadesini p ifadesine atarsak hata alırız. Çünük a, 5 e eşittir. Halbuki p ifadesi değer değil adres tutar. O yüzden de a'nın adresini p'ye atamamız gerekiyor. Herhangi bir ifadenin de adres bilgisine anpersan(&) ifadesiyle ulaşılır.

p = &a;

yaparak biz, a'nın adresini p'ye atadık. a'nın adresi derken biz aslında 5 değerinin bilgisayar hafızasındaki adresinin bulunduğu yeri p'ye atadık. p ifadesi de artık aynı adrese sahip olduğu için; *p ifadesi bize 5'i verecektir. Yani p bize 5'in adresini ve *p bize adresin sahip olduğu değeri verir.

Son olarak şu ekran görüntüsü aklınızda bazı şeylerin daha da netleşmesini sağlayacaktır diye düşünüyorum :


Pointer konusunun mantığı budur. Eğer aklınıza takılan yerler var ise, alt kısma yorum olarak yazabilirsiniz. Size elimden geldiğince yardımcı olmaya çalışırım.
Yazının devamını oku
Verilerin bilgisayar hafızasının belli bir bölümüne yerleştirilip saklanması olayıdır. Bu veriler birbiri ile bağlantılı olacak şekilde hafızaya yerleştirilir. İhtiyaç duyduğumuz herhani bir zamanda ise, en baştaki veriden başlayarak hafızanın o bölgesindeki diğer tüm verilere istediğimiz zaman ulaşabilme imkanını sağlayan bir veri yapısıdır.

Kısacası amaç, hafızada bir veri kümesi oluşturmak ve oluşturduğumuz bu veri kümesindeki, istediğimiz herhangi bir bilgiye ulaşmak.

Daha somut bir örnek vermek gerekirse, bir iş yerindeki personelleri düşünün. Tüm bu personellerin bilgilerini içeren bir dosya düşünün. O dosya, bizim veri kümemizdir. İhtiyaç duyduğumuz herhangi bir zamanda ise o dosyanın sayfalarını tek tek kurcalayarak istediğimiz zaman istediğimiz personelin bilgisine nasıl ulaşabiliyorsak, bilgisayar hafızasında oluşturacağımız veri kümemesindeki, istediğimiz bir veriye de aynı şekilde ulaşabileceğiz.

Veri kümesindeki tüm bilgiler birbirine şu mantıkla bağlanıyorlar :
Resmi büyütmek için üzerine tıklayınız.


Yapacağımız örnek üzerinde konuyu anlatmaya çalışacağım. Üstteki örnekte olduğu gibi çalışmamızı integer veriler üzerinde yapacağız. Zaten okullarda da genelde öyle gösterilir.

İlk önce Dugum adında bir sınıf oluşturalım. (Struct ile de yapılabilir.) Bu Liste bizim veri kümemiz olacak. Sınıfa düğüm adını vermek demek, oluşturacağımız listenin adı "Dugum"dur demek oluyor. Yani listemize "Dugum" adını verdik.Düğüm adlı sınıf yapımızdan düğümler oluşturacağız. Bu kısım size karışık gelmesin. Demek istediğim şey, "Dugum" adında bir listemiz var ve biz bu "Dugum" adını verdiğimiz listede kullanmak üzere, "Dugum" sınıfından çift bölmeli olan düğümlerden oluşturacağız. Düğümlerin birleşimi ise bize "listeyi" oluşturacaktır.

Bakınız :















Oluşturduğum liste içindeki düğümlerde ortak olarak kullanacağımız 2 farklı yapıya ihtiyaç duyacağız. Bunların biri, verileri saklayacak olan int tanımlı bir yapı olacak. Diğeri ise, bir sonraki düğüme ulaşmamızı sağlayacak olan bir pointer yapısı olacak.

Oluşturduğumuz listeden yola çıkarak her bir düğümü;

Dugum p1 =  new Dugum();

şeklinde oluşturacağız. Şuanda p1 adında bir düğüm oluşturmuş olduk.




Dugumlerimizi oluşturduktan sonra, her bir düğüme veri ataması yaptık.
Çünkü biz iliyoruz ki  her bir düğüm;
1- Veri saklar.
2 - Sonraki düğümün verisinin adresini saklar.

biz ilk önce veri atamalarını yaptık. Birinci düğüm olan p1'e 1 verisini atadık. p1 düğümünün verisi 1'dir dedik ve bilgisayar bellekte, p1 düğümünün veri kutucuğunda 1'yi sakladı.
p2 düğümüne 4 verisini atadık,
p3 düğümünün veri kısmı 3 bilgisini saklıyor,
p4 düğümü de 5 bilgisini içeriyor.

Daha sonra ise, p1 -> pSonraki = p2 ifadesinden başlamak üzere tüm düğümleri birbirine bağladık. Yani, p1 düğümünün adres saklayan kısmı olan 2. bölmesine; p2 verisinin adresini sakladık.

p2'nin verisi neydi? - p2'nin verisi 4'idi. Bir önceki aşamada p2 -> veri = 4 yaparak p2 düğümüne veri olarak 4'ü atamıştık çünkü. Dolayısıyla p1 düğümünün adres kısmı, 4 sayısının adresini tutuyor.

p2'düğümü ise, p4 verisinin adresini tutuyor.
p4 düğümü, p3 düğümünün verisinin adresini tutuyor.
p3 düğümü ise, adres kısmında hiçbir verinin adresini tutmuyor. Çünkü p3 düğümü listenin son düğmüdür ve kendisinden sonra başka düğüm gelmemektedir. p3'ün adres taşıyan kısmına bu yüzden de direkt olarak NULL yazıyoruz.

Dikkat ettiyseniz her bir düğüm bir sonraki düğümü işaret ederek aslında bir liste oluşturdular.
p1'den sonra p2'yi işaret ederek, aynı zamanda p1'den sonra p2 geliyor dedik.
p2'den sonra p4 geliyor dedik.
p4'ten sonra p3 geliyor dedik.
p3'ten sonra bir şey gelmiyor, NULL yazarakda başka bir düğüm gelmediğini belirttik.

Ben bu şekilde bağladım. Siz kafanıza göre daha farklı şekillerde de bağlayabilirsiniz düğümleri.

Gördüğünüz gibi, tüm düğümler birbiri ile bağlantı içinde oldu ve bir liste meydana geldi :


Liste İçinde Gezmek / Listedeki Tüm Verileri Konsolda Listelemek

Şimdide programı çalıştırıp, girdiğimiz tüm verileri yazacağımız kodlar aracılığıyla konsol ekranında listeleyeceğiz.

Verileri listelemek için sadece ilk düğümü bilmek bize yetecektir. Tek yönlü bağlı listelerde ilk düğüm çok önemlidir. Çünkü tüm işlemler ilk düğüm üzerinden gerçekleştiriliyor. İlk düğümü kaybetmek demek, listeyi kaybetmek demektir. Gezme işlemini de ilk düğümümüz olan p1'den başlatacağız.

Ben elemanları listelemek için yazmamız gereken kodu, ayrı bir fonksiyon oluşturarak yazacağım. Hepsini main içine yazıp, main içini karıştırmaktansa ayrı bir fonksiyonda yazmak göze daha hoş gelir. İsteyen kodları main içinde yazabilir. Ben ayrı bir fonksiyon oluşturacağım için ilk önce main'in hemen üst kısmında, yani class ile main arasında "listele" adında bir fonksiyon oluşturdum ve kodları da onun içine yazdım.

Bakınız :








*** Eğer siz de listeleme işlemini benim gibi bu şekilde ayrı bir fonksiyon içinde yapacaksınız, fonksiyonun çağrılıp ekrana basılması için, main kısmına listele(p1); yazmayı unutmayınız!

Burada bilmeniz gereken şey, p1 düğümünü olduğu gibi while içinde kullanmamanız gerektiğidir. Ben p1 düğümünü, pBas dügümüne atadım. Resimde de gördüğünüz üzere bunu fonksiyon içinde yaptım. Eğer siz bu while döngüsünü main içinde yaptıysanız, şunu yapmanız gerekiyor :

Dugum *pBas;
pBas = p1; 

daha sonra ise, pBas'ı while içinde kullanmanız gerekiyor. Bunu yapmamızdaki amaç, orjinal düğümümüz olan p1'i kaybetmemektir. Bundan sonraki yapacağımız ekleme, çıkarma vs. gibi işlemlerde hatalı sonuç çıkmasının önüne geçmektir.

pBas aslında yine p1'dir. Bunlar birbirinin aynısıdır. Bunu yaparak p1'i sonraki işlemlerde kullanmak üzere saklamış olduk. pBas ise, ilk dügüm olduğu için kendisinden başlanarak while döngüsü içinde tüm düğümlere tek tek uğrayıp verisini ekrana yazdırarak listeyi gezmiş olduk.

Şuanda pBas'ın p1 olduğunu düşünerek while döngüsünü inceleyelim.

Satır satır açıklayacak olursam;

13. Satır : While döngüsüne, pBas NULL olmadığı sürece verileri ekrana yazdırmaya devam et dedim.

15. Satır : pBas'ın o an için sahip olduğu veriyi yazdır anlamına geliyor.

16. Satır : pBas'tan sonraki veri hangisi ise onu al, pBas'a ata.


1. kez While içine girdiğimiz zaman;
pBas = p1 olduğu için, ekrana p1'in verisi olan 1 yazıldı.
pBas'a, p1'den sonraki düğüm olan p2 atandı ve pBas artık p2 olmuş oldu.


2. kez While içine girdiğimiz zaman;
pBas artık p2 olduğu için p2'nin verisi olan 4 ekrana yazıldı.
pBas'a, p2'den sonraki düğüm olan p4 atandı ve pBas artık p4 olmuş oldu.
(Daha önceki yaptığımız işlemlere dikkat ederseniz eğer, p2 -> pSonraki = p4 yapmıştık. O yüzden p2'den sonra p4 geldi. Rakamsal sıraya göre gitmiyoruz. Düğümleri bağladığımız sıraya göre ilerliyoruz.)


3. kez While içine girdiğimiz zaman;
pBas artık p4 olduğu için p4'nin verisi olan 5 ekrana yazıldı.
pBas'a, p2'den sonraki düğüm olan p3 atandı ve pBas artık p3 olmuş oldu.

4. kez While içine girdiğimiz zaman;
pBas artık p3 olduğu için p3'nin verisi olan 3 ekrana yazıldı.
pBas'a, p3'den sonraki düğümü atamayamıyoruz çünkü p3 listemizin son düğümüydü. Kendisinden sonra başka bir düğüm yok. Eğer hatırlarsanız, p3'ün adres kısmına herhangi bir düğümün verisinin adresini yazamadığımız için NULL yazmıştık. Bu sebeple pBas = NULL olmuş oldu.

pBas == NULL olduğu için ise, döngüye bir daha girmiyor program ve işlemimiz burada sonlanıyor.

----------------------------------------------------------------------------------------------------------------------

Listeye düğüm ekleme
Listeden düğüm silme
Araya düğüm ekleme
Aradan düğüm silme

işlemlerini ileriki zamanlarda başka bir konu başlığı altında, bu konun devamı olarak anlatmaya çalışacağım.

Benim anlatacaklarım şimdilik bu kadar. Umarım yeterince açıklayıcı ve faydalı olabilmişimdir. Eğer anlamadığınız yerler olursa aşağı yorum olarak bildirin. İnsalık halidir, yanlış yaptığım yerler olabilme ihtimali de vardır. Bu sebeple aklınıza takılan soruları hemen alt kısımdan yorum olarak bana iletebilirsiniz. Elimden geldiğince yardımcı olmaya çalışacağım.

Yazının devamını oku

İstatistikler

BLOGKAFEM.NET

© Copyright 2008-2018
Sitedeki yazıların her hakkı BLOGKAFEM.NET sitesine aittir.
Kopyalanması halinde lütfen kaynak gösteriniz.
DMCA.com Protection Status
Anasayfa | Hakkımda | Bizden Haberler | Reklam | İletişim