You are on page 1of 20

Fork(), Exec(), Wait() Sistem

Çağrıları
İşletim Sistemleri Dersi
FORK()
• fork(), herhangi bir parametre almayan bir sistem çağrısıdır.
• Çağrıldığı andan itibaren işletim sistemi tarafından, ana processin bir
kopyası oluşturulur.
• fork() çağrısını yapan process parent, ve bu çağrı ardından oluşan yeni
process ise child olarak adlandırılır.
• fork() çağrısı yapıldığı andan itibaren, oluşan child process, parent’ın
kaldığı yerden devam edecek şekilde bir kopya haline gelir.
FORK()
• fork() çalıştırıldığında aşağıdaki dönüş değerleri ortaya çıkmaktadır:
• fork() çağrısı başarısız olursa dönüş değeri -1 ’dir
• çağrı başarılı olursa;
• parent process için dönüş değeri, yeni oluşan child processin ID’si,
• child process için dönüş değeri 0 ’dır.

• fork() çağrısının dönüş değerleri konusunda şu yargıya varabiliriz:


fork_donus_degeri > 0 : bu sonuç parent process içinde döndürülür
fork_donus_degeri == 0 : bu sonuç child process içinde döndürülür
fork_donus_degeri == -1 : çağrı başarısız oldu ve child oluşmadı. parent içinde döndürülür
FORK()
• Basit bir parent-child process aşağıdaki şekilde oluşturulabilir

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
printf("Hello, World \n");
int fork_donus_degeri = fork();
printf("Bye Bye, World \n");
printf("fork donus degeri : %d", fork_donus_degeri);
return 0;
}

• int fork_donus_degeri = fork();


Bu dönüş değerlerine göre parent ve child processlerimize farklı işlemler yaptırmamız mümkün olabilmektedir
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int main(void) {
int fork_donus_degeri = fork();
int sonuc;
if (fork_donus_degeri == 0) { // burasi child processte calisir cunku == 0 degerini o saglayabilir
sonuc = 0;
int i;
for(i=0;i<10;i++) {
sleep(1);
sonuc = sonuc + 1;
printf("child_dongu_%d : sonuc : %d \n", i, sonuc);
}
printf("CHILD SONUCU : %d \n", sonuc);
}
else if (fork_donus_degeri > 0) { // burasi parent processte calisir cunku > 0 degerini o saglayabilir
sonuc = 1;
int i;
for(i=0;i<10;i++) {
sleep(1);
sonuc = sonuc * 2;
printf("parent_dongu_%d : sonuc : %d \n", i, sonuc);
}
printf("PARENT SONUCU : %d \n", sonuc);
}
else if (fork_donus_degeri == -1) {
printf("ERROR : \n %d", errno);
return 1;
}
return 0;
}
SLEEP()
• Yukarıdaki örnek üzerinde yer alan sleep() komutu, parametre olarak
verilen sayı boyunca saniye cinsinden processi uyku moduna alır.
sleep(1);
• Bir process her zaman diğerinden önce sonlanabilir. Eğer bir process
bittikten sonra ikincinin bitmesi için biraz süre varsa, bu durumda shell
komut satırı sanki tüm program bitmiş gibi açılır. Ardından diğer
process işlemini göstererek devam eder.
• Yukarıdaki örneğin çıktısı aşağıdaki gibidir.

• Bir parent process’in, kendi child process’inden önce işleyişini tamamlaması ve kapanması
istenmeyen bir durumdur. Bu nedele böyle durumlardan kaçınmak için parent tarafından
kullanılabilecek bir wait(&donus_degeri) komutu vardır
• Bir parent process’in, kendi child process’inden önce işleyişini
tamamlaması ve kapanması istenmeyen bir durumdur. Bu nedenle
böyle durumlardan kaçınmak için parent tarafından kullanılabilecek
bir wait(&donus_degeri) komutu vardır
wait(&status)
• Üst proses bir alt prosesin sonlanmasını bekleyebilir.
• wait fonksiyonunun prototipi şöyledir:
#include <sys/wait.h>
wait(int *status);

• Fonksiyon parametre olarak sonlanan prosesin çıkış kodunun yerleştirileceği int türden


nesnenin adresini alır. 
• wait fonksiyonu herhangi bir alt proses sonlanana kadar kendisini çağıran thread’i bloke
etmektedir.
• Sonlanan prosesin id değeri, geri dönüş değeri olarak verilir. Ayrıca, parametre NULL adres
olarak geçilebilir. Bu durumda fonksiyon  bize sonlanan prosesin çıkış kodunu vermez.
wait(&status)
• Aşağıda alt prosesin çıkış kodununun ekrana yazdırıldığı bir örnek görüyorsunuz:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include "general.h"

int main(void)
{
    pid_t pidChild;

    if ((pidChild = fork()) < 0) 


        err_sys("fork");

    if (pidChild == 0) {            /* Alt proses */


        sleep(5);
        exit(100);
    }
    else {                          /* Ust proses */
        int stat;

        printf("Alt prosesin sonlanmasi bekleniyor...\n");


        if (wait(&stat) < 0) 
            err_sys("wait");

        printf("Alt prosesin sonlanma kodu: %d\n", WEXITSTATUS(stat));


    }
    
    return 0;
}
EXEC()
• Çeşitli varyasyonları bulunan bu sistem çağrısı ile bir process içinde yeni bir program çağrısı
yapılabilmektedir. (Çağrı yapılan, yeni bir process değil, yeni bir programdır.)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
int fork_donus_degeri = fork();
if (fork_donus_degeri == 0) { // burasi child processte calisir
execl("/bin/ls", "/bin/ls","-la", NULL);
}
return 0;
}
EXEC()
• fork() ile oluşan yeni bir process, parent process ile aynıdır ve kod,
stack ve kullanılan veriler child process içinde yer alır.
• exec*(..) ile bir child processin sahip olduğu kod, veri ve stack
değiştirilebilir.
• Bunun anlamı, child process parent’ın bir kopyası olarak doğmuştur
ancak artık başka bir işlem yürütmektedir ve exec*(..) bitene kadar
child beklemededir.
EXEC()
• fork işlemi sonrasında alt ve üst prosesler aynı program kodunu
çalıştırıyor durumda olurlar. Halbuki pek çok uygulamada programcı
yaratmış olduğu alt prosesin farklı bir program kodunu çalıştırmasını
ister. İşte exec fonksiyonları prosesin başka bir program olarak
çalışmaya devam etmesini sağlamaktadır. 
• exec işlemleri sonrasında prosesin id değeri ve kontrol bloğu
değişmez. Prosesin kod, data ve bash alanları çalıştırılabilen
(executable) dosyadan alınarak yüklenir. Proses artık yaşamını başka
bir program olarak sürdürür. 
• Tüm exec fonksiyonlarının prototipleri <unistd.h> dosyası içersindedir.
EXEC()
• Exec komutu aldığı parametrelere ve gördüğü işlevlere göre 6 farklı şekilde çalışırlar.
Bunlar ve aldıkları parametreler aşağıdaki gibidir.

int execl(const char *path, const char *arg0, … /*,(char *) 0 */);


int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, … /*, (char *) 0, char *const envp[] */);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char * file, const char *arg0, … /*, (char *) 0 */);
int execvp(const char *file, char *const argv[]);
EXEC()
• exec fonksiyonlarının l’li (execl, execle, execlp) ve v’li
(execv, execve, execvp) biçimleri vardır.
• Bunların l’li biçimleri komut satırı argümanlarını bir liste olarak, v’li
biçimleri ise bir dizi olarak alırlar.
• Ayrıca bazı exec fonksiyon isimlerinin ‘e’ ya da ‘p’ harfiyle
sonlandırıldığını göreceksiniz. Fonksiyonların e’li biçimleri çevre
değişkenlerini (environment variables) de programcıdan
istemektedir. p’li biçimler çalıştırılabilen dosyanın yerinin
belirlenmesinde PATH çevre değişkenlerini dikkate alırlar.
• fork() ve exec*() işlemlerinin
yürümesi yandaki
şekilde ifade edildiği gibidir.
Getpid()
Mevcut process için process_ID’yi döndürür. Örnek bir kod aşağıdaki şekildedir.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
int pid;
pid = getpid();
printf("ilk alınan pid : %d\n", pid);
int fork_donus_degeri = fork();
if (fork_donus_degeri == 0) { // burasi child processte calisir
pid = getpid();
printf("CHILD pid : %d\n", pid);
}
else if (fork_donus_degeri > 0) { // burasi parent processte calisir
pid = getppid();
printf("PARENT pid : %d\n", pid);
}
else if (fork_donus_degeri == -1) {
printf("ERROR : \n"); return 1;
}
pid = getpid(); printf("son alinan pid : %d\n", pid);
return 0;
}
getppid() , getpgrp()
• getppid(), mevcut bir child process’in parent process ID’sini döndürür.
• getpgrp(), bir process grubunun (parent ve child içeren) grup ID’sini
döndürür.
• Bir grubun grup ID’si, o child processleri oluşturan parent process’in
ID’sidir.
Örnekler
• fork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
pid_t cocuk_pid;
printf(“Ana sürecin pid = %d\n”, (int)getpid() );
cocuk_pid=fork();
if (cocuk_pid!=0){
printf(“burası ana sürectir, süreç id pid=%d\n”,(int)getpid());
printf(“çocuk sürecin idsi pid = %d\n”,(int)cocuk_pid); }
else{
printf(“burası çocuk süreçtir, pid=%d\n”, (int)getpid()); }
return 0;
}
Waitpid()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void err_sys(const char *msg)


{
    perror(msg);
    fflush(stdout);
    exit(EXIT_FAILURE);
}

int main(void)
{
    pid_t pidChild;

    if ((pidChild = fork()) < 0) 


        err_sys("fork");

    if (pidChild == 0) {              /* Alt proses */


        sleep(5);
        exit(100);
    }
    else {                            /* Ust proses */
        int stat;

        printf("Alt prosesin sonlanmasi bekleniyor...\n");


        if (waitpid(pidChild, &stat, 0) < 0) 
            err_sys("waitpid");

           }
    
    return 0;
}

You might also like