PROCESS YARATIMI (TEKRAR): Gecen haftaki dersten hatırlayabileceğiniz üzere, bir process başka bir process yaratabilmesi için UNIX sistemlerinde fork() sistem çağrısı kullaılıyordu. Başka bir process yaratan processe parent, yaratılan processe ise child adı verilir. Processlerin aynı anda çalışması ile ilgili iki yaklaşım söz konusudur : Parent child process(ler) ile aynı anda çalışmaya devam edebilir. Parent child process(ler) bitene kadar bekleyebilir. Aşağıdaki şekilde, kendi ürettiği bir child processin bitimine kadar bekleyen bir parent process örneği gösterilmektedir :
THREAD MEKANİZMASI Neden Threadlere ihtiyaç duyuyoruz? Normalde bir process belirli bir adres alanı ve iş akışının var olduğu yani sadece bir thread kontrolünün olduğu bir yapıya sahiptir. Tek bir thread kontrolü ile anlatılmak istenen, program kodunda tek bir noktayı gösteren sadece bir tane program counter register değeri vardır ve bu değer çalışma anında her yeni instruction ile artar. Ama bazen aynı adres alanı içerisinde parallel halde çalışan çoklu thread kontrolüne ihtiyaç duyulur. Thread, bir programın kendini aynı anda çalışan birden fazla parçaya bölerek bu işe uygun bir işlemcinin bu özellikten istifade ederek işlemleri daha kisa sürede gerçekleştirebilmesini sağlar. (Örneğin bir thread'de grafik işlemlerini yaparken, diğer bir thread'de gerekli program hesaplamalarını yapması gibi). Thread ve process arasındaki fark bir işletim sisteminden diğerine değişmekle birlikte genel olarak thread yaratılışı ve kaynakları paylaşması açısından process'den ayrılır. Threadlere aynı zamanda hafif processler de denir, çünkü thread yaratımı ve threadler arası geçiş processlere gore çok daha ekonomiktir. Çoklu thread'ler paralel olarak pek çok bilgisayar sisteminde uygulanabilir. Tek işlemci kullanıldığı durumlarda çok thread' li uygulama zaman dilimleme ile gerçekleştirilir; tek işlemci faklı thread' lar arasında çok hızlı geçiş yapar ve bu durumda işlemler gerçekte olmasa bile eş zamanlı koşuluyormuş izlenimi verir. Çok işlemcili sistemlerde farklı thread' ler farklı işlemciler üzerinde eş zamanlı olarak çalışabilir. Pek çok modern işletim sistemi bir iş düzenleyicisi yardımıyla hem zaman dilimleme hemde çok işlemcili thread' lemeyi desteklemektedir. İşletim sistem çekirdeği (kernel) sistem çağrıları vasıtası ile programcıya thread' leri kontrol etme imkanı sağlamaktadır. Bunun yokluğunda programlar, zamanlatıcılar, sinyaller veya diğer yöntemleri kullanarak kendi çalışmalarını sonlandırabilirler. Bunlara user threadler denilir. Eğer thread kernel tarafından oluşturuluyor ise de kernel thread adını alır. Threadler, yapılan işlemlerde paralelliğe ihtiyaç olduğu, program modelini daha az komplike hale getirmeye çalışıldığında kullanılması avantajlı mekanizmalardır. Ayrıca thread yaratımı process yaratılmasına oranla çok daha hızlıdır çünkü threadler içerisinde kendilerine bağlı kaynakları barındırmazlar.
Bir processde de olduğu gibi, her thread 3 farklı durumda bulunabilir, ready, blocked(waiting: başka bir dış olayın I/O tamamlanması gibi- bitmesi bekleyebilir yahut başka bir threadin blokesini kaldırmasını bekliyebilir) ve running. Her program çalışmaya tek threadli process olarak başlar, sonrasında ise thread_create() gibi fonksiyonlar kullanarak yeni threadler oluşturulabilir. MULTITHREADING Multitasking, bir işletim sisteminin aynı anda birden fazla programı çalıştırabilmesidir. Bunun için sırada bekleyen uygulamalara sırayla işlemci zamanından bir kaç milisaniyelik zaman verilir ve kullanıcı açısından bütün programlar aynı anda çalışıyormuş gibi görünür. Aslında bir seferde bir program çalışmasına rağmen, işlemci kullanıcıdan çok çok daha hızlı olduğu için bu durum farkedilmez. Multithreading ise bir program içinde birden fazla işlemin çalışabilmesidir. Multitasking'de bir program çalışırken sadece kendisine ayrılan bellek üzerinde kendi değişkenleriyle çalışır. Multithreading'de ise işlemler aynı program içinde çalıştıklarından dolayı aynı belleği ve aynı değişkenleri paylaşabilirler. Her process en az bir thread'den oluşmak zorundadır ve zorunlu olan bu thread'e main thread denir. Birden fazla thread varsa uygulama multi-threaded olarak adlandırılır. Tek threadli bir process ve multithreading uygulanan bir process arasındaki fark şekilde görülebilir.
Multithreaded bir process içerisindeki her thread aynı adres alanına, global verilere, açılmış aynı dosyalara sahiptir, buna kıyasla her threadin kendine özel program counter register değeri, stact ve stack pointerı, local verileri, ve CPU register kümesi vardır. Aşağıdaki şekilde bunların tam bir özeti bulunmaktadır : Multithreading mekanizmaları 3 farklı sisteme ayrılır : Many - To - One Threading Bu multithread mekanizmasında işletim sisteminin çekirdeği(kernel) multithread mekanizmasından habersizdir. İşletim sistemi basit olarak bir process yahut thread çalıştırdığını düşünmektedir. Ancak user alanında thread kütüphanesi sayesinde birden fazla thread oluşturulup kullanılabilmekte ve threadler arası geçiş yapılabilmektedir. Solaris Green Threadleri, GNU Portable Threadleri ve Linux üzerindeki Pthread kütüphanesi de bu mekanizmadadır. Bu mekanizmanın önemli bir dezavantajı vardır, eğer threadlerden biri bloke olur ise, kernel işlemin sadece
bir thread taarafından yapıldığını düşündüğünden threadler arası geçiş yapamaz, böylece process içerisindeki tüm threadler bloke olur. One To One Threading Her bir user threadi için kernel tarafında bir threadin oluşturulduğu mekanizmadır. Bu mekanizmanın kullanılabilmesi için, işletim sisteminin kernel tarafında thread mekanizmasını desteklemesi gerekmektedir. Windows NT/XP/2000 threadleri, Linux threadleri ve Solaris 9 threadleri bu gruba girmektedir. Avantajları : Bir thread tarafından yapılan bir system çağrısı aynı process içerisindeki diğer threadleri bloke etmez. Bir process birden fazla işlemci kullanabilir. Threadlerin yaratılışı, yok edilişi ve birbirleri arasındaki geçişi processlere gore daha ekonomiktir.
Dezavantajları : Kernel threadlerinin yaratılışı, yok edilişi ve birbirleri arasındaki geçişi user threadlerine gore daha maliyetlidir. CPU zaman bölüm algoritmaları adil değildir : Her threade aynı zaman dilimi verilir. Bu sebeple çok sayıda threadi olan işlemler daha az sayıda threadleri olan işlemlere gore daha çok CPU zamanı kazanmış olurlar. Many To Many Threading Bu mekanizmanın kullanılabilmesi için kernel multithreadingi desteklemek zorundadır. Fakat one-to-one model de olduğu gibi her bir user threadine karşılık bir tane kernel threadi olmak zorunda değildir. N tane user threadine karşılık M tane kernel threadi oluşturulmakta (M<=N) ve user threadi önce n. thread ile daha sonar n+1. thread ile ilgilenebilmektedir, user threadleri değiştirilebilir.işletim sistemi gerekli sayıda kernel threadinin oluşmasına ve birçok kernel threadinin user threadine eşleşmesine izin verir. IRIX, HP-UX ve Tru64 UNIX threadleri bu gruba girmektedir.
THREAD KOPYALANMASI Threadler kopyalanırken, temelde var olan soru şudur : Eğer multi-threaded bir program içerisinde yer alan bir thread fork() çağrısını kullanırsa, oluşan yeni process bütün threadlerin kopyasını mı taşır yoksa sadece çağrıyı yapan thread mi kopyalanır? Bu sorunun cevabı kullanılan UNIX versiyonunda gizlidir. Bazı UNIX sistemlerinde 2 çeşit fork() vardır, öyleki biri bütün threadlerin kopyalayarak, diğeri ise sadece çağrıyı yapan threadi kopyalayarak fork() çağrısını sonuçlandırır. Eğer exec() metodu fork() çağrısından hemen sonar yapılırsa, bütü threadleri kopyalamak gerekli değildir.
THREADLERIN DURDURULMASI Bir threadin durdurulmasından kasıt, thread işini bitirmeden önce iptal edilmesidir. Durdurulacak threade target thread adı verilir. 2 şekilde yapılabilir : Eş zamanlı Olmayan Durdurma : Bir thread hemen target threadi durdurur. Böyle bir durumda şöyle problemler ortaya çıkabilir; durdurma paylaşılan herhangi bir datanın update edilmesi sırasında olabilir veya işletim sistemi durdurulan threadden ele geçirdiği tüm kaynakları geri istemiyebilir. Ertelenen Durdurma : Target thread periyodik olarak durdurulup durdurmayacağını kontrol edebilir. Böylece threade kendi kendini durdurma adına bir fırsat verilmiş olur. Fakat durdurma aşaması sadece işlemin sonlanmasının problem yaratmayacağından emin olunan cancellation points adı verilen güvenli noktalarda yapılır. THREAD HAVUZLARI Bir processin istediği anda istediği kadar thread yaratması sistemde bir problem oluşturabilir çünkü istenilen servise uygun bir thread yaratmak zaman alabilir veya limitsiz threadlerin sayısı system kaynakları tüketebilir. Bu problem çözmek için thread havuzları denen kavramlar yaratılmıştır. Bir thread havuzu processin başlangıcında limitli sayıda threadin hazır olarak yaratıldığı bir alandır. Eğer process çalışma anında iken bir threade ihtiyaç duyarsa, bu havuzdan alır, threadin yerine getireceği servis tamamlandığında da tekrar bu havuza geri bırakılır. Eğer process bir threade ihtiyaç duyarken havuzda herhangi bir thread bulunmazsa, havuza işini tamamlayan bir thread dönene kadar beklemek zorundadır. Process her defasında kendi threadlerini yaratmak zorunda kalmayacağından ve thread sayısında bir limit söz konusu olduğundan sistemde hızlı bir çözüm üretilmiş olur.
LINUX THREADLERİ Linux işletim sisteminde task kavramı threadler yerine kullanılır. Thread yaratımı clone() system çağrısı tarafından yapılır. Clone() child bir taskın, parentının adres alanını paylaşmasını sağlar, bu sebeple yeni process ayrı bir thread mantığında çalışır. Hangi alanların paylaşılacağı ise bu system çağrısının flag değerlerinde belirlenir. Fork() sistem çağrısı ise parentın adres alanın kopyası ile ayrı bir process yaratır.linux de kernel 2.2 versiyonu ile beraber thread desteğini sağlamaya başlamıştır. Aslında Linux de process ve thread ayrımı yoktur, her biri task adı altında birleşir. Clone() system çağrısı haricinde Linux multithreading mekanizmasını desteklememektedir. Fakat user seviyesinde multithreading desteğinin sağlanması için pthreads denilen kütüphaneler kullanılmaktadır. Clone() fonksyionunun parametric yapısı aşağıdaki gibidir : Int clone(int (*fn)(void*), void* child_stack, int flags, void* args) Fonksiyonun ilk parametresi bir fonksiyon pointer yani child process olarak çalıştırılacak fonksiyondur. Fonksiyonun geri dönüş değeri int, aldığı parametre ise türü olmayan bir pointerdır. Clone() fonksiyonunun 4. parametresi fn ile gösterilen fonksiyona aktarılacak olan parametredir. Bilindiği gibi threadler aynı kod ve very alanını kullanmalarına rağmen kendilerine özel stack alanları da vardır. İşte clone() fonksiyonunun 2. parametresi bu stacki kullanacak bir alan belirlemektedir.3. parametre ise daha önce bahsedilen flag değerleridir. Bu değerler CLONE_XXX biçiminde öntanımlı değerlere sahiptir. Bu değerler birbirileri ile mantıksal veya işlemine tabi tutularak birden fazla flagi içerecek biçimde verilir. Fonksiyonları prototipi ve bu değerler <sched.h> dosyası içindedir.