Fork()

Linux.fista
Versio hetkellä 15. lokakuuta 2016 kello 23.42 – tehnyt Oselotti (keskustelu | muokkaukset) (→‎Taustaprosessin luominen: ISO C90 kieltää esittelyjen ja koodin sekoittamisen)
(ero) ← Vanhempi versio | Nykyinen versio (ero) | Uudempi versio → (ero)
Siirry navigaatioon Siirry hakuun

Fork() on SVr4, 4.3BSD ja POSIX.1-2001 -standardien mukainen funktio C-kielessä. Sillä luodaan ohjelmalle kutsun suorituskohtaan lapsiprosessi vastaavassa tilassa. Funktion esittely löytyy unistd.h-otsikkotiedostosta.

Prototyyppi

pid_t fork()

Paluuarvo

Palautusarvo (tyyppiä pid_t) on -1 virheen tapahtuessa, muuten se vastaa lapsiprosessin prosessitunnusta. Lapsiprosessille palautusarvo näkyy nollana (0x0).

Käyttö

Fork on se tapa, jolla uusia prosesseja luodaan unixeissa. Jos lapsiprosessin pitää suorittaa toista ohjelmaa, se käyttää exec-kutsua forkin ja mahdollisten siivoustoimien jälkeen. Vaikka prosessin kopioiminen ennen kopion korvaamista toisella saattaa tuntua resurssien haaskaukselta, se ei sitä ole: lapsiprosessin muistiavaruus osoittaa samaa fyysistä muistia, kunnes lapsiprosessi kirjoittaa siihen, eikä käyttämätöntä muistia siis tarvitse kopioida ("Copy-on-Write").

Fork-kutsun lisäksi on olemassa clone-kutsu, jolla voi tarkemmin määritellä mitkä resurssit jäävät prosessien yhteisiksi. Tällä kutsulla luodaan säikeet.

Esimerkki

Luodaan seuraavanlainen C-ohjelma:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
        pid_t pid;
        printf("Luodaan taustaprosessi\n");
        pid = fork();
        if (pid==0)     /* Lapsiprosessille pid näkyy nollana */
                printf("Olen lapsiprosessi\n");

        else if (pid>0)    /* Forkkaus onnistui, tämä on isäntä */
                printf("Olen isäntäprosessi\n");
        printf("Terve Linux.fi\n");
        return 0;
}

Tallennetaan koodi tiedostoon fork.c ja käännetään se komennolla gcc fork.c -o fork. Nyt ohjelman tuloste olisi seuraavanlainen:

Luodaan taustaprosessi
Olen lapsiprosessi
Terve Linux.fi
Olen isäntäprosessi
Terve Linux.fi

Lisäämällä ehtolauseisiin yhden tulostusrivin sijaan vaikkapa silmukassa ajettavaa koodia (esim. while(1) printf("Lapsiprosessi");) huomataan, että prosesseja ajetaan vuorotellen.

Taustaprosessin luominen

fork-funktion ajavan ohjelman toinen osa jää taustalle ja alkuperäinen ohjelma voidaan sammuttaa. Esimerkkikoodi:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
        pid_t pid;
        printf("Luodaan taustaprosessi\n");
        pid = fork();

        if (pid > 0) return 0;      /* Isäntäprosessi loppuu */
        if (pid < 0) return -1;     /* Forkkaus ei onnistunut 0_o */

        while(1) { }   /* Ikuinen silmukka */
        return 0;
}

Tallennetaan koodi tiedostoon taustaprosessi.c, käännetään se komennolla gcc taustaprosessi.c -o taustaprosessi ja ajetaan se (./taustaprosessi). Tuloste on seuraavanlainen:

$ ./taustaprosessi
Luodaan taustaprosessi
$

Ohjelma siis näyttää sammuvan heti tulostettuaan tekstirivin. Tutkitaanpa asiaa hieman tarkemmin. Aja komento

ps aux | grep taustaprosessi

Jolloin huomaat, että taustaprosessi-niminen ohjelma on yhä ajossa. Myös top:in prosessilistauksessa sen pitäisi näkyä yläpäässä kuluttamassa paljon prosessoritehoa. Voit tappaa sen komennolla killall taustaprosessi.