Thursday 27 December 2007

LINUX Programlamağa Giriş– Süreçler 4

Ali Rıza SARAL(1)


(1) Neil Matthew ve Richard Stones, Beginning Linux Programming ‘den faydalanarak derlenmiştir.

Yeni Süreçler Başlatış
Bir program içinden başka bir programın çalışışına neden olabiliriz ve böylece sistem kütüphanesi fonksiyonunu kullanarak yeni bir süreç yaratabiliriz.

#include
int system (const char *string);

Sistem fonksiyonu kendisine bir karakter dizisi olarak geçirilen komutu koşturur ve bitişi için bekler. Komut aşağıdaki şekilde

$ sh -c string

bir kabuğa verilmiş gibi çalıştırılır. Sistem eğer komutu koşturmak için bir kabuk açılamazsa 127 ve eğer başka bir hata oluşursa -1 döndürür. Başka durumlarda, sistem komutun geri dönüş kodunu döndürür.

Örnek:
#include
#include
int main()
{
printf(“Running ps with system\n”);
system(“ps -ax”);
printf(“Done.\n”);
exit(0);
}

Çıktı:
$ ./system1
Running ps with system
PID TTY STAT TIME COMMAND
1 ? S 0:05 init
2 ? SW 0:00 [keventd]
...
1262 pts/1 S 0:00 /bin/bash
1273 pts/2 S 0:00 su -
1274 pts/2 S 0:00 -bash
1463 pts/1 S 0:00 oclock -transparent -geometry 135x135-10+40
1465 pts/1 S 0:01 emacs Makefile
1480 pts/1 S 0:00 ./system1
1481 pts/1 R 0:00 ps -ax
Done.

Alternatif:
System1.c içindeki fonksiyon çağrısını şununla değiştiriniz:

system(“ps -ax &”);

Çıktı:
$ ./system2
Running ps with system
PID TTY STAT TIME COMMAND
1 ? S 0:05 init
2 ? SW 0:00 [keventd]
...
Done.
$ 1246 ? S 0:00 kdeinit: klipper -icon klipper -miniicon klipper
1274 pts/2 S 0:00 -bash
1463 pts/1 S 0:00 oclock -transparent -geometry 135x135-10+40
1465 pts/1 S 0:01 emacs Makefile
1484 pts/1 R 0:00 ps -ax
.
Bir Süreç Görüntüsünün Yerine Geçiş
Exec başlığı altında büyük bir ilişkili fonksiyonlar ailesi var. Süreçleri başlatış ve program başlatış değişkenlerini Sunuş açısından farklılaşırlar. Bir exec fonksiyonu şu andaki sürecin yerine yeni bir süreç koyar, bir patika veya dosya başlangıç değişkeni belirleyerek .

Genelde, sistem komutunu kullanmak süreçleri başlatmak için idealden çok uzak bir yaklaşımdır.

Bu fonksiyonlar iki gruba aittir. execl, execlp, ve execle sonu boş işaret edici ile biten değişik sayıda başlangıç değişkeni alırlar. Eğer exec fonksiyonunu ps programını başlatmak için kullanmak isterseniz, aşağıda gösterilen altı exec ailesinin birinden seçebilirsiniz.

#include
/* Example of an argument list */
/* Note that we need a program name for argv[0] */
char *const ps_argv[] =
{“ps”, “-ax”, 0};
/* Example environment, not terribly useful */
char *const ps_envp[] =
{“PATH=/bin:/usr/bin”, “TERM=console”, 0};
/* Possible calls to exec functions */
execl(“/bin/ps”, “ps”, “-ax”, 0); /* assumes ps is in /bin */
execlp(“ps”, “ps”, “-ax”, 0); /* assumes /bin is in PATH */
execle(“/bin/ps”, “ps”, “-ax”, 0, ps_envp); /* passes own environment */
execv(“/bin/ps”, ps_argv);
execvp(“ps”, ps_argv);
execve(“/bin/ps”, ps_argv, ps_envp);

Alternatif:
#include
#include
int main()
{
printf(“Running ps with execlp\n”);
execlp(“ps”, “ps”, “-ax”, 0);
printf(“Done.\n”);
exit(0);
}

Pexec.c’yi çalıştırınca, alışılagelmiş ps çıktısını alırız fakat done çıkmaz. Ayrıca çıkışta pexec’ten bahsedilmez.

$ ./pexec
Running ps with execlp
PID TTY STAT TIME COMMAND
1 ? S 0:05 init
2 ? SW 0:00 [keventd]
...
1262 pts/1 S 0:00 /bin/bash
1273 pts/2 S 0:00 su -
1274 pts/2 S 0:00 -bash
1463 pts/1 S 0:00 oclock -transparent -geometry 135x135-10+40
1465 pts/1 S 0:01 emacs Makefile
1514 pts/1 R 0:00 ps –ax

Süreç Görüntüsünü Katlayış
Aynı anda birden çok fonksiyon çalıştıran süreçler kullanmak için, bağlar(threads) kullanabiliriz veya init’in yaptığı gibi program içinde tamamen ayrı bir süreç yaratırız, exec durumunda olduğu gibi, şu anda çalışan bağın yerine geçirmek yerine.

Fork’u çağırarak yeni bir süreç yaratabiliriz. Bu sistem çağrısı şu andaki sürecin çok sayıda özellikleri ile süreç tablosunda yeni bir hane açarak şu andaki süreci tekrar yaratır.
Yeni süreç hemen hemen aslı ile aynıdır, aynı kodu çalıştırır fakat kendi adres alanı, ortamı, ve dosya tanımlayıcıları ile. Exec fonksiyonları ile birlikte fork yeni süreçler yaratmak için ihtiyacımız olan yegane şeydir.

#include
#include
pid_t fork(void);

Şekil 11-2’de gördüğünüz gibi, ebeveyn içinde fork’a yapolan çağrı yeni çocuk sürecin SüreçKimlikNo’sunu (PID) döndürür. Yeni süreç aslının aynı şekilde çalışmağa devam eder, çocuk sürecin fork’a çağrısı 0 döndürmek istisnası ile. Bu hem ebeveynin hem de çocuğun kimin kim olduğunu belirleyişini mümkün kılar.
Şekil 11-2

Eğer fork başaramazsa -1 döndürür. Bu bir ebeveynin sahip olabileceği çocukların üst sınırı (COCUK_MAX (CHILD_MAX)) nedeni ile bu durum yaygındır, bu durumda errno EAGAIN değerine eşitlenir. Eğer süreç tablosunda bir hane için yeterli yer yoksa, veya yeterli sanal bellek yoksa, errno değişkeni ENOMEM ile eşitlenir.

Tipik bir fork kod parçası:

pid_t new_pid;
new_pid = fork();
switch(new_pid) {
case -1 : /* Error */
break;
case 0 : /* We are child */
break;
default : /* We are parent */
break;
}

Örnek: fork1.c
#include
#include
#include
int main()
{
pid_t pid;
char *message;
int n;
printf(“fork program starting\n”);
pid = fork();
switch(pid)
{
case -1:
perror(“fork failed”);
exit(1);
case 0:
message = “This is the child”;
n = 5;
break;
default:
message = “This is the parent”;
n = 3;
break;
}
for(; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}
Bu program iki süreç olarak çalışır. Bir çocuk doğar ve bir mesajı 5 defa basar. Asıl süreç(ebeveyn) mesajı yalnız üç defa basar. Ebeveyn süreç çocuk mesajlarının hepsini basmadan önce biter, dolayısıyla bir sonraki kabuk sorgucusu(prompt) çıkış ile karışarak belirir.

$ ./fork1
fork program starting
This is the parent
This is the child
This is the parent
This is the child
This is the parent
This is the child
$ This is the child
This is the child