İşletim Sistemleri. Dr. Binnur Kurt binnur.kurt@gmail.com. Omega Eğitim ve Danışmanlık http://www.omegaegitim.com. İşletim Sistemleri



Benzer belgeler
İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık İşletim Sistemleri

Proses. Prosesler 2. İşletim Sistemleri

PROSESLER. Proses. Proses

Giriş. İplik Modeli. geleneksel işletim sistemlerinde her prosesin özel adres uzayı ve tek akış kontrolü var.

Bilgisayar İşletim Sistemleri BLG 312

Bilgisayar İşletim Sistemleri BLG 312

Giriş. geleneksel işletim sistemlerinde her prosesin. aynı adres uzayında birden fazla akış kontrolü gerekebilir

İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık İşletim Sistemleri

YZM 3102 İşletim Sistemleri

İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık İşletim Sistemleri

1. Aşağıdaki program parçacığını çalıştırdığınızda result ve param değişkenlerinin aldığı en son değerleri ve programın çıktısını yazınız.

Yrd. Doç. Dr. Caner ÖZCAN

Yrd. Doç. Dr. Caner ÖZCAN

İşletim Sistemleri. İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık

Bil101 Bilgisayar Yazılımı I. M. Erdem ÇORAPÇIOĞLU Bilgisayar Yüksek Mühendisi

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

while(), do-while(), for() M.İLKUÇAR 2010 MAKU-MYO

Linux'ta Kabuk ve Kabuk Programlama

BMÜ-111 Algoritma ve Programlama. Bölüm 5. Tek Boyutlu Diziler

Öğr. Gör. Serkan AKSU 1

BMÜ-111 ALGORİTMA VE PROGRAMLAMA AKIŞ KONTROLÜ YRD. DOÇ. DR. İLHAN AYDIN

C++ Giriş Ders 1 MSGSU Fizik Bölümü Ferhat ÖZOK Kullanılacak kaynak: Published by Juan Soulié

BIL1202 ALGORİTMA VE PROGRAMLAMAYA GİRİŞ

Multicore/Multithread Programlama

BLM 112- Programlama Dilleri II. Hafta 5 İşaretçiler (Pointers)

Bölüm 24. Java Ağ Uygulamaları 24.1 Java Appletleri. Bir Applet in Yaşam Döngüsü:

ELN1001 BİLGİSAYAR PROGRAMLAMA I

Programın Akışının Denetimi. Bir arada yürütülmesi istenen deyimleri içeren bir yapıdır. Söz dizimi şöyledir:

Karşılaştırma İşlemleri ve Koşullu İfadeler

Bölüm 3: İşlemler Operating System Concepts with Java 8th Edition 3.1 Silberschatz, Galvin and Gagne 2009

Bölüm 3: İşlemler Operating System Concepts with Java 8th Edition 3.1 Silberschatz, Galvin and Gagne 2009

Lab7 DOĞU AKDENİZ ÜNİVERSİTESİ BİLGİSAYAR VE TEKNOLOJİ YÜKSEKOKULU BİLGİSAYAR PROGRAMCILIĞI. BTEP212 Java. Uygulama1: package javaapplication58;

DÖNGÜLER BMÜ-111 ALGORİTMA VE PROGRAMLAMA-I YRD. DOÇ. DR. İLHAN AYDIN

BİL132 Bilgisayar Programlama II

// hataları işaret eden referans

MAT213 BİLGİSAYAR PROGRAMLAMA I DERSİ Ders 1: Programlamaya Giriş

Nesne tabanlı programlama nesneleri kullanan programlamayı içerir. Bir nesne farklı olarak tanımlanabilen gerçek dünyadaki bir varlıktır.

BLM-112 PROGRAMLAMA DİLLERİ II. Ders-3 İşaretçiler (Pointer) (Kısım-2)

DÖNGÜLER (LOOPS) while(), do-while(), for(), foreach()

İŞLETİM SİSTEMLERİ. (Operating Systems)

Bölüm 11. Soyut veri tipleri ve kapsülleme kavramları ISBN

BMH-303 Nesneye Yönelik Programlama

Programlama Dillerinde Kullanılan Veri Tipleri

Bölüm 10: PHP ile Veritabanı Uygulamaları

Java 2 Standart Edition SDK Kurulum ve Java ya Giriş

YZM 2105 Nesneye Yönelik Programlama

/*Aşağıda ki kodları doğru şekilde anlar ve kullanırsanız java da sınıfları biraz da olsa anlamış olursunuz.*/

Görsel Programlama DERS 03. Görsel Programlama - Ders03/ 1

İşletim Sistemleri (Operating Systems)

YZM 2116 Veri Yapıları

Temel Bilgisayar Programlama Final Sınavı Çalışma Notları

NESNEYE YÖNELİK PROGRAMLAMA

Algoritma ve Programlamaya Giriş II JAVA İLE PROGRAMLAMA. Muhammet BAYKARA

Yazılım Kodlama ve İ simlendirme Standartları v1.0

BMS-302 İleri Web Programlama. İş Parçacığı (Thread) ve Soket (Socket) Programlama

Pointer Kavramı. Veri Yapıları

Java da İşleçler, Ders #3 (4 Kasım 2009)

BM-209 Nesne Yönelimli Programlama. Yrd. Doç. Dr. İbrahim Alper Doğru Gazi Üniversitesi Teknoloji Fakültesi Bilgisayar Mühendisliği Bölümü

MAT213 Bilgisayar Programlama I

BİL-141 Bilgisayar Programlama I (Java)

İçerik. Java da İşleçler, İşleçler. Aritmetik İşleçler - 1. Aritmetik İşleçler - 2. Geçen ders: Bu ders: BS-515 Nesneye Yönelik Programlama

Paket Erişimleri. Altuğ B. Altıntaş 2003 Java ve Yazılım Tasarımı - Bölüm 4 1

Java da Soyutlama ( Abstraction ) ve Çok-biçimlilik ( Polymorphism )

Windows'da çalışırken pek çok durumda bir işe başlamadan önce işletim sisteminin o işe ilişkin bilgileri depolayacağı bir alan yaratması gerekir.

İŞ SIRALAMA. İş Sıralamanın Amaçları. İş Sıralama Türleri - 1. İş Sıralama. İş Sıralama Türleri - 2

Yrd. Doç. Dr. A. Burak İNNER

Özyineleme (Recursion)

HSancak Nesne Tabanlı Programlama I Ders Notları

PAKET TRANSFER SİSTEMİ

Yrd. Doç. Dr. A. Burak İNNER

BM102 BİLGİSAYAR PROGRAMLAMA II LABORATUVAR UYGULAMALARI. 3Hafta

İşletim Sistemleri. Hazırlayan: M. Ali Akcayol Gazi Üniversitesi Bilgisayar Mühendisliği Bölümü

Çoktan Seçmeli Değerlendirme Soruları Akış Şemaları İle Algoritma Geliştirme Örnekleri Giriş 39 1.Gündelik Hayattan Algoritma Örnekleri 39 2.Say

Bölüm 6. Karma. Olcay Taner Yıldız. O. T. Yıldız, C && Java ile Veri Yapılarına Giriş, Boğaziçi Üniversitesi Yayınevi, / 31

Veritabanı. Ders 2 VERİTABANI

JAVA PROGRAMLAMA DİLİ ÖZELLİKLERİ

İşletim Sistemlerine Giriş

MOBİL UYGULAMA GELİŞTİRME

BİL-142 Bilgisayar Programlama II

BTEP243 Ders 3. class Yazım Kuralı:

C++ Dersi: Nesne Tabanlı Programlama

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

PROGRAMLAMAYA GİRİŞ DERS 2

İŞLETİM SİSTEMLERİ (POSIX THREADS v1)

if (ad == "Sabri") Console.WriteLine("Merhaba Sabri. Ne zamandır gözükmüyodun...");

İşletim Sistemi. BTEP205 - İşletim Sistemleri

Erişim konusunda iki taraf vardır:

Süreç 1 Kavramı ve Oluşturma Yöntemleri

Pascalda oluşturulacak dosyalar değişkenler gibi programın başında tanımlanır.

BİL-141 Bilgisayar Programlama I (Java)

ECLIPSE PROGRAMININ ÇALIŞTIRILMASI

Java Programlamaya Giriş

Kodlanacak programlama dilinin kaynaklarından faydalanılarak kod yazımı yapılır.

BĠLGĠSAYAR PROGRAMLAMA II C++ Programlamaya GiriĢ Published by Juan Soulié

HSancak Nesne Tabanlı Programlama I Ders Notları

Linux Assembly Programlamaya Giriş

Sistem Programlama. Kesmeler(Interrupts): Kesme mikro işlemcinin üzerinde çalıştığı koda ara vererek başka bir kodu çalıştırması işlemidir.

ENF102 TEMEL BİLGİSAYAR BİLİMLERİ VE C/ C++ PROGRAMLAMA DİLİ. Gazi Üniversitesi Mühendislik Fakültesi Bilgisayar Mühendisliği Bölümü

Üst Düzey Programlama

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

Transkript:

İşletim Sistemleri Dr. Binnur Kurt binnur.kurt@gmail.com Omega Eğitim ve Danışmanlık http://www.omegaegitim.com 1 S a y f a

İÇİNDEKİLER 1. İşletim Sistemi 2. Kabuk 3. 4. İplikler 5. İplikler Arası Eş Zamanlama 6. Arası İletişim 7. İş Sıralama 8. Arası Eş zamanlama 9. Bellek Yönetimi 10. Dosya Sistemi 11. Soket Haberleşme 2 S a y f a

BÖLÜM 3 Bölümün Amacı Bölüm sonunda aşağıdaki konular öğrenilmiş olacaktır: Proses ve prosesin durumları Linux da proses yönetimi arasında ebeveyn-çocuk ilişkisi Linux da çok prosesli uygulama geliştirme Java 9 da prosesler üzerinde işlemler yapabilmek 3 S a y f a

3.1 Giriş İşletim sisteminin temel görevinin başta işlemci olmak üzere sistem kaynaklarını paylaştırmak olduğunu söylemiştik. İşletim sistemi tasarlanırken bir dizi genel tasarım hedefleri gözetilir. Bu isterlerin başında çok görevlilik gelir. İşletim sisteminin birden fazla görevi çalıştırması istenir. İşletim sistemi üzerinde çok sayıda uygulamanın çalışması istenir. Bu çalışan uygulamalar, işletim sisteminde, proses olarak adlandırılır. Burada işletim sistemi, tek ya da çok çekirdekli ya da işlemcili bir sistem üzerinde çalışıyor olabilir. Eğer tek işlemci yada çekirdek varsa aynı anda birden fazla proses çalışamaz. Çekirdek içinde proses sıralayıcı tarafından yönetilen bir önceliklendirilmiş kuyruk bulunur. Her proses belirli bir süre işlemciyi kullanır ve süresi dolduğunda işlemciyi terk eder. Bazen bir prosesin zamanı dolmasa da işlemciyi terk etmesi gerekebilir. Bu konuyu daha sonra daha detaylı inceleyeceğiz. Kuyruktaki proseslerden biri, işlemciyi bir sonra kullanacak proses olarak seçilir ve işlemci ona verilir. İşlemciyi terk eden proses bu önceliklendirilmiş kuyruktaki yerini alır ve sıra tekrar kendisine gelen kadar bekler. Böylelikle prosesler işlemciyi zamanda paylaşarak ve vakit buldukça çalışarak ellerindeki işleri tamamlamaya çalışırlar. Birden fazla çekirdek yada işlemcinin olduğu sistemlerde, çekirdek sayısı kadar kuyruk bulunur ve çekirdek sayısı kadar proses paralel olarak çalışabilir. 3.2 Proses Modeli Her bir uygulamanın çalıştırılması için bir prosesin yaratılması gerektirir. Ama bir uygulama çok prosesli olabilir. Bir proses bir ya da daha fazla çocuk proses yaratabilir. Böylelikle prosesler arasında ebeveyn çocuk ilişkisi yaratılmış olunur. Proses yaratıldığında bellekte proses için yer ayrılır. Bunun dışında çekirdek her bir proses için proses ile ilgili bilgileri sakladığı bir tablo oluşturur. Bu tablo proses tablosu olarak adlandırılır. Prosesin bellek modeli bir işlemciden diğerine değişmekle birlikte genel olarak Şekil-3.1 de verilen bir modele sahiptir. Burada Yığın (=Stack) yerel değişkenlerin, fonksiyon çağrılarında parametre aktarımı, dönüş adresinin ve dönüş değerinin saklanması için kullanılır. Yığının çalışması otomatik olarak gerçekleşir. Yerel değişkenler erimi başladığı yerde otomatik olarak yığında yaratılır, erimi dışına çıkıldığında ise yine otomatik olarak yok edilir. Bu yüzden bu tür değişkenler bazen geçici ya da otomatik değişken olarak da adlandırılır. Heap, dinamik bellek kullanımı için kullanılır. Bu alanın yönetiminden programcı sorumludur. Programcı, C de malloc() ve free() fonksiyonlarını, C++ da ise new ve delete operatörlerini kullanarak ihtiyacı kadar alanı alır ve kullanımı bitince ise aldığı alanı geri vermekle sorumludur. Bu söylemesi kolay ancak gerçeklemesi zor bir sorumluluktur. Bu nedenle C/C++ ile geliştirilen uygulamalarda dikkat edilmez ise bellek kaçağı oluşabilir. Bu özellikle servis tipi hiç sonlamayacak biçimde tasarlanan yazılımlar için büyük sorun oluşturur. Birkaç sekizlik bir kaçak, uzun dönemde yetersiz bellek hatası alınmasına neden olabilir. Text alanda fonksiyonlar yer alır. Data bölmesinde ise global değişkenler ve fonksiyonlarda static olarak tanımlanan değişkenler saklanır. 4 S a y f a

1 int x; 2 static int b = 4; 3 4 main() { 5 int y; 6 static int z; 7 8 y = b; 9 z = foo(y); 10 11 12 foo( int p ) { 13 int a; 14 a = p + 2; 15 return(a); 16 Stack Heap Data Text main() y foo() p a x b z main() { foo() { Şekil-3.1 Proses Bellek Modeli uygulamaların görevlerini kodlama için ağır sıklet elemanlardır. Bir proses fork() sistem çağrısını kullanarak çocuk proses yaratabilir. fork sistem çağrısı prosesin bellek görüntüsünün bire bir kopyasını çıkarır. Bu nedenle fork ile proses yaratmak maliyetlidir. Diğer bir maliyet bağlam anahtarlamada karşılaşılır. İşlemciyi kullanan proses süresi dolup işlemciyi terk ederken sıra tekrar kendisine geldiğinde kaldığı yerden devam edebilmesi için bağlamının saklanması gerekir. Bağlam, saklayıcılar, yığın göstergesi, program sayacı gibi işlemci içindeki elemanlardan oluşur. Bunlar bellekte saklanır. Böylelikle sıra tekrar kendisinde geldiğinde, prosesin bellekte saklanan bu bağlamı işlemciye geri yüklenerek, prosesin kaldığı yerden devam etmesi sağlanır. Prosesin bağlamı kalabalık olduğu için anahtarlama maliyeti de yüksektir. Bu yüzden çok prosesli yapıya farklı bir seçenek olarak çok lifli (=thread) yapılar kullanılabilir. Lifler proseslere göre hafif sıklet elemanlardır. Bir lif yaratıldığında onun için sadece yeni bir yığın yaratılır. Bir lif prosesin heap, text ve data alanlarını paylaşır. Her lifin ise kendi yığını vardır. Linux da yaratılabilecek proses sayısının ve yığın büyüklüğünün bir değeri ve sınırı vardır. Bu sınırları ulimit komutunu kullanarak öğrenebilir ve yine bu komutu kullanarak değiştirebiliriz: [student@server1 ~]$ ulimit -a core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15781 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 5 S a y f a

pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 1024 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited Bu değerleri değiştirmek için komutun çıktısında listelenen ile başlayan parantez içinde yazılı olan seçenek kullanılır. Örneğin bir kullanıcının yaratabileceği proses sayısı yukarıdaki listeden 1024 olarak okuyoruz. Bunu 2048 olarak değiştirmek için ulimit u 2048 komutunu çalıştırıyoruz: [student@server1 ~]$ ulimit -u 1024 [student@server1 ~]$ ulimit -u 2048 [student@server1 ~]$ ulimit -u 2048 Her bir lif yaratıldığında kendi yığını ile yaratılıyordu. Bu yığının boyutunu yukarıdaki komut çıktısından 8M olarak okuyoruz. Bunu 1M olarak değiştirmek için ulimit s 1024 komutunu çalıştırıyoruz: [student@server1 ~]$ ulimit -s 8192 [student@server1 ~]$ ulimit -s 1024 [student@server1 ~]$ ulimit -s 1024 Linux da uygulama geliştirmek için aşağıdaki modellerden biri kullanılır. i. Çok Prosesli Programlama Modeli ii. Tek Prosesli Çok Lifli Programlama Modeli iii. Çok Prosesli Çok Lifli Programlama Modeli Bu modellerin biri birlerine göre kazanım ve yitimleri vardır. Çok prosesli modelin yitimi proses yaratma ve prosesler arasında bağlam anahtarlama maliyetidir. Çok lifli programlamada lifler işlemciyi daha verimli kullanır. Üstelik lif yaratmak daha düşük maliyeti vardır. Buna karşılık liflerden biri başarısız olursa uygulama da başarısız olur ve sonlanması gerekir. Bu nedenle genellikle (iii) ile verilen modeli tercih edilir. Kritik görevler ayrı prosesler olarak kodlanır. Her bir proses liflerden oluşur. Örneğin Oracle veritabanı, chrome ve firefox web tarayıcıları bu modele göre gerçeklenmişlerdir. 3.3 Linux da le Çalışmak Sistemde çalışan tüm proseslerin listesini almak için ps komutunu fe seçeneği ile birlikte kullanıyoruz: student@server1 ~]$ ps -fe more UID PID PPID C STIME TTY TIME CMD root 1 0 0 10:22? 00:00:02 /sbin/init root 2 0 0 10:22? 00:00:00 [kthreadd] root 3 2 0 10:22? 00:00:00 [ksoftirqd/0]... root 17 2 0 10:22? 00:00:00 [watchdog/2] root 18 2 0 10:22? 00:00:00 [ksoftirqd/2] 6 S a y f a

root 19 2 0 10:22? 00:00:00 [migration/2]... pgrep komutu ile prosesler arasında arama işlemi yapılabilir. in bir kısmı arka planda çalışan proseslerdir. Bu proseslerin ismi d ile biter. Sonu d ile biten proseslerin listesini almak için pgrep i kullanabiliriz: [student@server1 ~]$ pgrep -l "d$" 2 kthreadd 10 rcu_sched 32 kintegrityd 33 kblockd... 3493 gvfsd 3531 restorecond 3535 vmtoolsd Burada $ özel bir semboldür ve katarın sonunu ifade eder. Komutun çıktısında ilk sütun proses kimlik numarasını ve ikinci sütun ise prosesin adını göstermektedir. i sonlandırmak için kill komutundan yararlanılır. kill komutu bir proses sinyal göndermek için kullanılır. Bir proses gönderilebilecek sinyallerin listesini almak için kill l komutunu kullanıyoruz: Bu sinyallerden 9 (SIGKILL) sinyalini alan bir proses doğrudan sonlanır: [student@server1 ~]$ for i in 1 2 3 ; do gcalctool & done [1] 12358 [2] 12359 [3] 12360 [student@server1 ~]$ kill -9 12358 [student@server1 ~]$ kill -9 12359 [1] Killed gcalctool [student@server1 ~]$ kill -9 12360 [2]- Killed gcalctool [student@server1 ~]$ [3]+ Killed gcalctool i proses ismi ile sonlandırmanın yolu pkill komutunu kullanmaktır: 7 S a y f a

[student@server1 ~]$ for i in 1 2 3 ; do gcalctool & done [1] 12374 [2] 12375 [3] 12376 [student@server1 ~]$ pkill gcalctool [student@server1 ~]$ [1] Terminated gcalctool [2]- Terminated gcalctool [3]+ Terminated gcalctool [student@server1 ~]$ arasında kimlik numarası 1 olan proses özel bir prosestir. init proses olarak adlandırılır. Tüm başlangıç işlemlerinden ve yapılandırmadan sorumludur. Başlangıç işlerinin yapılandırılmasından sorumlu dosya ise /etc/inittab dosyasıdır. Burada çalışma düzeyleri (=run level) tanımları yer alır. Her bir servisin hangi çalışma düzeyinde çalışacağı ise chkconfig komutu ile listelenebilir ve düzenlenebilir. Aşağıdaki örnekte mysql servisinin çalışma düzeyleri listeleniyor ve daha sonra tüm düzeylerde kapatılıyor. [student@server1 ~]$ chkconfig --list mysql mysql 0:off 1:off 2:on 3:on 4:on 5:on 6:off [student@server1 ~]$chkconfig --level 2345 mysql off [student@server1 ~]$ chkconfig --list mysql mysql 0:off 1:off 2:off 3:off 4:off 5:off 6:off Çalışma düzeyleri arasında geçiş için ise init komutundan yararlanılır. Klasik Unix sistemlerinde 5 çalışma düzeyi yer alır. 1 den 5 e doğru yeni servisler açılır. 5 den 1 e doğru servisler kapatılır. 1 düzeyinde tüm bilgisayar ağı kapalıdır ve çekirdek tek kullanıcılı olarak çalışır. Sisteme saldırı olduğunda ya da yeni bir çekirdek kurulması gerektiğinde işletim sistemi 1 düzeyine init 1 komutu ile indirilir. 1 düzeyinden 3 düzeyine çıkmak için init 3 komutu çalıştırılır. init 0 sistemi kapatırken init 6 işletim sistemini yeniden başlatır. 2 düzeyinde sistem çok kullanıcılı olur ve ağ erişilebilir. 3 düzeyinde NFS yeteneği gelir. 5 düzeyinde ise X11 sunucusu çalışır. X11 sunucusu grafik arayüzün çalışmasını sağlar. 3.4 Linux da Proses Yaratılması Linux da proses yaratmak için fork sistem çağrısını kullanıyoruz. fork sistem çağrısı yapıldığında çekirdeğin yürüttüğü işlemler: Proses tablosunda yer ayırılır Çocuk prosese sistemde tekil yeni bir kimlik numarası atanır Anne prosesin bağlamının kopyası çıkarılır. Dosya erişimi ile ilgili sayaçları düzenlenir fork() sistem çağrısı, anneye çocuğun kimliğini, çocuğa da 0 değerini döndürür. fork() sistem çağrısı, eğer proses yaratılırken hata durumu oluşursa, -1 değerini döndürür. fork() sistem çağrısının kullanıldığı basit bir örnek Kod 3.1 de verilmiştir. 8 S a y f a

Kod 3.1: #include <unistd.h> #include <stdio.h> int f; int main (void){ printf("program çalışıyor: Kimliğim= %d\n", getpid()); f=fork(); if (f==0) /*çocuk*/ { sleep(1); printf("\nben çocuk. Kimliğim= %d", getpid()); printf("\nannemin kimliği= %d\n", getppid()); exit(0); else if (f>0)/* anne */ { printf("\nben anne. Kimliğim= %d", getpid()); printf("\nannemin kimliği= %d", getppid()); printf("\nçocuğumun kimliği= %d\n", f); sleep(2); printf("\nbitti.\n"); exit(0); return(0); 3.5 Linux da Proses Sonlandırılması Bazen bir proses elindeki işi bitirmeden sonlanması gerekir. Genellikle bu durum kritik bir hata oluştuğunda gerçekleştirilir, hata iletisini kayda alıp proses sonlandırılır. Bu gibi durumlarda exit, _exit, atexit ve abort çağrılarını kullanıyoruz: i. exit() stdio nun tampon bellek alanlarını giriş/çıkış cihazlarına yazar ve uygulamayı _exit() çağrısı ile sonlandırır. void exit(int status); ii. _exit() Tüm açık dosyaları kapatır ve prosesi sonlandırır. Ebeveyn prosese SIGCHLD sinyali gönderir. Sinyaller prosesler arasında haberleşme için kullanılan tekniklerden biridir. Unix işletim sistemin bir prosese gönderilebilecek 9 S a y f a

proseslerin listesini almak için kill l komutu kullanıldığını daha önce çalışmıştık. Burada her bir sinyalin önceden tanımlı bir anlamı bulunmaktadır. void _exit(int status); iii. atexit() Proses sonlanırken çalıştırılmak üzere bir fonksiyonu kaydeder. Bu fonksiyon genellikle alınan sistem kaynaklarını serbest bırakacak kodu içerir. Kaynağa örnek olarak veritabanı bağlantısı ve soket verilebilir. Kod 3.2 de atexit çağrısının kullanımına ilişkin örnek bir uygulama verilmiştir. int atexit(void (*func)(void)); iv. abort() Tüm dosyaları kapatır, prosesi sonlandırır ve hata ayıklamada kullanılmak üzere prosesin bellek dökümünü bir dosyaya alır. Bu dosya daha sonra bir hata ayıklama aracı ile açılarak, hatanın kaynağı bulunmaya çalışılır. Dolayısı ile abort çağrısı sadece hata ayıklama amacıyla kullanılmalıdır. void abort(void); Kod 3.2: #include <string.h> #include <unistd.h> void cleanup() { char *message = "cleanup invoked\n"; write(stdout_fileno, message, strlen(message)); main() { atexit(cleanup); exit(0); 3.6 Proses Kimliğine Ulaşmak Bazen çalışmakta olan prosesin kimlik bilgisine erişmek gerekebilir. Bu durumda getpid, getppid, getpgrp ve getpgid fonksiyonları kullanılır. Şimdi bu fonksiyonların işlevlerine bir bakalım: 1. getpid() Çalışmakta olan prosesin kimlik numarasını verir. 10 S a y f a

pid_t getpid(void); 2. getppid() Çalışmakta olan prosesin ebeveyn prosesinin kimlik numarasını verir. pid_t getppid(void); getpid ve getppid çağrılarının kullanıldığı basit bir örnek Kod-3.3 de verilmiştir. 3. getpgrp() Prosesin yer aldığı grubun grup numarasını verir. #include <sys/types.h> #include <unistd.h> pid_t getpgrp(void); 4. getpgid() Proses grubunun kimlik numarasını verir. pid_t getpgid(pid_t pid); int setpgid(pid_t pid, pid_t pgid); Komut satırında ls sort uniq komutu çalıştırılırsa, 3 proses yaratılır ve bu prosesler aralarında boru (=pipe) olarak adlandırılan özel bir veri yapısı üzerinden haberleşirler: [student@server1 ~]$ ls sort uniq Desktop Documents Downloads... Bu üç proses ls, sort ve uniq komutlarına karşılık olarak yaratılır. Bu üç proses bir grup oluşturur (Şekil-3.2). Bu grubun kimliğine ulaşmak için getpgid çağrısını kullanıyoruz. Örneğe baktığımızda ls prosesinin kimliği 108, sort prosesinin kimliği 549 ve uniq prosesinin kimliği 3615 dir. Proses grubunun kimliği ise 240 tır. ls sort uniq PID 108 549 3615 PGID 240 240 240 Proses grup 240 549 3615 Şekil-3.2 Grup prosesler ve kimlik numaraları 108 Grup lideri 11 S a y f a

Kod 3.3: #include <unistd.h> #include <stdio.h> int main() { printf("my pid is: %d\n", getpid()); printf("my parent pid is: %d\n", getppid()); 3.7 Bir Prosesin Sonlanmasını Beklemek Ebeveyn prosesin sonlanmadan önce gerçekleştirmesi gereken bir sorumluluğu bulunmaktadır. Yarattığı çocuk proseslerin sonlanmasını beklemelidir. İşletim sistemi çekirdeği yaratılan her bir proses ile ilgili bir kayıt tutmaktadır. Normalde bir proses sonlandığında bu kayıt otomatik olarak silinir. Ancak çocuk prosesin sonlanma durumlarını izlenebilmesi için çocuk proses sonlandığında proses tablosundan kaydı silinmez. Bu sorumluluk ebeveyn prosese aittir. Ebeveyn proses bu sorumluluğunu wait ve waitpid çağrıları ile yerine getirir. Eğer ebeveyn proses bu sorumluluğunu yerine getirmez ve çocuk prosesin sonlanmasından önce sona ererse, çocuk prosesle ilgli bilgiler proses tablosundan silinemez. Unix işletim sisteminde, bu durumdaki prosesler, zombi proses olarak adlandırılır. 1. wait() Herhangi bir çocuk proses sonlandığında, sonlanan çocuk prosesin kimlik numarası ile dönülür. #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat_loc); 2. waitpid() waitpid çağrısında wait çağrısından farklı olarak belirli bir prosesin sonlanması beklenebilir. #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid,int *stat_loc,int options); Birinci parametrenin değerine farklı tercihler verilebilir: i. pid = -1 Herhangi bir çocuk proses sonlandığında waitpid çağrısından sonlanan çocuk prosesin kimlik numarası ile dönülür. ii. pid >0 Birinci parametrenin bu değeri sonlanması beklenen prosesin kimliğini tanımlar. iii. pid = 0 12 S a y f a

Çağıran prosesin bulunduğu proses grubundaki herhangi bir proses sonlandığında döner. iv. pid < 0 Birinci parametre olarak negatif bir sayı verildiğinde, bu sayının mutlak değerinin tanımladığı proses grubundan, herhangi bir proses sonlandığında, sonlanan prosesin kimlik numarası ile döner. waitpid çağrısı bloke çalışır. İstenilen proses sonlanana kadar çağrıyı yapan proses askıda kalır. Bu bazen istenmeyen durumdur. Üçüncü parametre olarak WNOHANG değeri verilirse, çağrının yapıldığı anda sonlanan herhangi bir proses yoksa, çağrıyı yapan proses çalışmaya devam eder, askıya alınmaz. Bu şekilde yoklamalı çalışılabilir. waitpid çağrısının kullanıldığı bir örnek Kod-3.4 de verilmiştir. Örnek uygulamada önce bir çocuk proses oluşturmakta ve ardından sonlanmasını beklemektedir. Kod 3.4: #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <unistd.h> int main() { pid_t pid; int status; /* fork() a child */ switch(pid = fork()) { case -1: perror("fork"); exit(1); /* in child */ case 0: execlp("ls", "ls", "-F", (char *)NULL); perror("execlp"); exit(1); /* parent */ default: break; if (waitpid(pid, &status, 0) == -1) { perror("waitpid"); exit(1); 13 S a y f a

if (WIFSIGNALED(status)) { printf("ls terminated by signal %d.\n", WTERMSIG(status)); else if (WIFEXITED(status)) { printf("ls exited with status %d.\n", WEXITSTATUS(status)); else if (WIFSTOPPED(status)) { printf("ls stopped by signal %d.\n", WSTOPSIG(status)); return 0; 3.8 Java 9'da Process API'deki Yenilikler Bu bölümde Java 9 da Process API'ye getirilmesi planlanan yeniliklere göz atacağız. İşletim sisteminde çalışan uygulamalar proses olarak adlandırılır. JDK, 1.0 sürümünden itibaren proseslerle çalışmak için bize java.lang.process soyutlaması sunmuş olsa da, prosesin kimlik bilgisini (PID, Process ID) elde etmek gibi basit bir işlem için bile içinde bir çözüm bulamıyoruz. Çalışan uygulamanın PID değerini, çok dolaylı bir yoldan, sorunlu bir şekilde elde etmek durumunda kalırız: import java.lang.management.managementfactory; public class GetPID { private static final int PID = 0; private static final int HOST = 1; public static void main(string[] args) { String name = ManagementFactory.getRuntimeMXBean().getName(); String[] parts = name.split("@"); int pid = Integer.parseInt(parts[PID]); String host = parts[host]; System.out.println("PID : " + pid); System.out.println("Host: " + host); Java 9'da ProcessHandle sınıfı ile tanışıyoruz. Bu sınıfı kullanarak, örneğin, çalışan uygulamanın PID değerine basit ve sorunsuz bir şekilde ulaşabiliriz: public class GetPID { public static void main(string[] args) { System.err.println("PID: " + ProcessHandle.current().getPid()); 14 S a y f a

ProcessHandle sınıfı kullanılarak, işletim sistemindeki tüm proses bilgilerine ulaşılabilinir. Aşağıda bu yeni sınıf yardımı ile neler yapabileceğimize bir bakalım. Java 9 API'leri elbette Java 8 ile gelen tüm yeniliklerden yararlanıyor: Stream API, Lambda ifadeleri, MapReduce çatısı, Optional, CompletableFuture, Time API ve diğerleri. İşletim sisteminde çalışan proseslerin sayısı public class PrintNumberOfProcesses { public static void main(string[] args) { long numberofprocesses = ProcessHandle.allProcesses().count(); System.out.println("Number of processes: " + numberofprocesses); İşletim sisteminde çalışan prosesleri yaratan komutların listesi public class ListAllCommands { public static void main(string[] args) { Consumer<String> printcommand = command -> { Path path = Paths.get(command); System.out.println(path.getFileName()); ; ProcessHandle.allProcesses().filter( p -> p.info().command().ispresent() ).map( p -> process.info().command().get() ).distinct().sorted().foreach(printcommand); İşletim sistemindeki tüm proseslerin listesi public class ListAllProcesses { public static void main(string[] args) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd- HH:mm:ss").withZone(ZoneId.systemDefault()); Consumer<String> printuser = user -> { System.out.println("User: " + user); ; Consumer<String> printcmd = cmd -> { System.out.println("Command: " + cmd); ; Consumer<String> printcmdline = cmdln -> { System.out.println("Command line: " + cmdln); ; Consumer<String[]> printargs = arguments -> { System.out.println("Arguments: " 15 S a y f a

+ Arrays.toString(arguments)); ; Consumer<Instant> printinstant = inst -> { System.out.println("Start time: " + formatter.format(inst)); ; Consumer<Duration> printcpu = duration -> { System.out.println("CPU time (millisec): " + duration.tomillis()); ; Consumer<Info> printinfo = info -> { info.user().ifpresent(printuser); info.command().ifpresent(printcmd); info.commandline().ifpresent(printcmdline); info.arguments().ifpresent(printargs); info.startinstant().ifpresent(printinstant); info.totalcpuduration().ifpresent(printcpu); System.out.println(); ; ProcessHandle.allProcesses().filter(p -> p.isalive()).map(p -> p.info()).foreach(printinfo); İşletim sisteminde şu an çalışan prosesler arasında en uzun süredir çalışan proses public class LongestRunningProcess { public static void main(string[] args) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss").withZone(ZoneId.systemDefault()); Consumer<String> printuser = user -> { System.out.println("User: " + user); ; Consumer<String> printcmd = cmd -> { System.out.println("Command: " + cmd); ; Consumer<String> printcmdline = cmdln -> { System.out.println("Command line: " + cmdln); ; Consumer<String[]> printargs = arguments -> { System.out.println("Arguments: " + Arrays.toString(arguments)); ; Consumer<Instant> printinstant = inst -> { System.out.println("Start time: " + formatter.format(inst)); ; Consumer<Duration> printcpu = duration -> { System.out.println("CPU time (millisec): " + duration.tomillis()); 16 S a y f a

; Consumer<Info> printinfo = info -> { info.user().ifpresent(printuser); info.command().ifpresent(printcmd); info.commandline().ifpresent(printcmdline); info.arguments().ifpresent(printargs); info.startinstant().ifpresent(printinstant); info.totalcpuduration().ifpresent(printcpu); System.out.println(); ; Instant now= Instant.now(); Optional<Info> processinfo= ProcessHandle.allProcesses().map( p -> p.info() ).filter(info -> info.startinstant().ispresent()).max( (p,q) -> q.startinstant().orelse(now).compareto(p.startinstant().orelse(now))); processinfo.ifpresent(printinfo); İşletim sisteminde şu an çalışan prosesler arasında en çok işlemci zamanını kullanan proses public class MostCpuConsumingProcess { public static void main(string[] args) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH:mm:ss").withZone(ZoneId.systemDefault()); Consumer<String> printuser = user -> { System.out.println("User: " + user); ; Consumer<String> printcmd = cmd -> { System.out.println("Command: " + cmd); ; Consumer<String> printcmdline = cmdln -> { System.out.println("Command line: " + cmdln); ; Consumer<String[]> printargs = arguments -> { System.out.println("Arguments: " + Arrays.toString(arguments)); ; Consumer<Instant> printinstant = inst -> { System.out.println("Start time: " + formatter.format(inst)); ; Consumer<Duration> printcpu = duration -> { System.out.println("CPU time (millisec): " + duration.tomillis()); ; Consumer<ProcessHandle.Info> printinfo = info -> { info.user().ifpresent(printuser); info.command().ifpresent(printcmd); 17 S a y f a

info.commandline().ifpresent(printcmdline); info.arguments().ifpresent(printargs); info.startinstant().ifpresent(printinstant); info.totalcpuduration().ifpresent(printcpu); System.out.println(); ; Optional<ProcessHandle.Info> processinfo = ProcessHandle.allProcesses().map(p -> p.info()).filter(info -> info.totalcpuduration().ispresent()).max((p, q) -> p.totalcpuduration().orelse(duration.zero).compareto( q.totalcpuduration().orelse(duration.zero))); processinfo.ifpresent(printinfo); Komut adı verilen tüm prosesleri sonlandırmak public class KillProcess { public static void main(string[] args) { if (args.length==0){ System.out.println("Usage: "); System.out.println( "ProcessKill <list of process names>"); System.out.println( "Example: \n\tprocesskill calc.exe mspaint.exe"); Predicate<ProcessHandle> processcriteria = p -> { Optional<String> cmd = p.info().command(); if (cmd.ispresent()) { Path path = Paths.get(cmd.get()); return Arrays.stream(args).anyMatch(arg -> path.getfilename().tostring().equals(arg) ); return false; ; ProcessHandle.allProcesses().filter(p -> p.isalive()).filter(processcriteria).foreach(processhandle::destroyforcibly); Verilen komutu çalıştıran ve bekçi köpeği olarak izleyen uygulama public class WatchDog { public static void main(string[] args) throws Exception { String cmd = args[0]; 18 S a y f a

do { Process process = Runtime.getRuntime().exec(cmd); ProcessHandle ph = process.tohandle(); CompletableFuture<ProcessHandle> onexit = ph.onexit(); onexit.get(); System.err.println("Exit value: " + process.exitvalue()); while (true); 19 S a y f a