Ero sivun ”Fork()” versioiden välillä

Linux.fista
Siirry navigaatioon Siirry hakuun
pEi muokkausyhteenvetoa
(→‎Esimerkki: source tagit)
Rivi 14: Rivi 14:
=== Esimerkki ===
=== Esimerkki ===
Luodaan seuraavanlainen C-ohjelma:
Luodaan seuraavanlainen C-ohjelma:
<pre>
<source lang="c">
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
Rivi 29: Rivi 29:
         return 0;
         return 0;
}
}
</pre>
</source>
Tallennetaan koodi tiedostoon <tt>fork.c</tt> ja käännetään se komennolla <tt>[[gcc]] fork.c -o fork</tt>. Nyt ohjelman tuloste olisi seuraavanlainen:
Tallennetaan koodi tiedostoon <tt>fork.c</tt> ja käännetään se komennolla <tt>[[gcc]] fork.c -o fork</tt>. Nyt ohjelman tuloste olisi seuraavanlainen:
<pre>
<pre>

Versio 18. elokuuta 2016 kello 22.10

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>

int main() {
        printf("Luodaan taustaprosessi\n");
        pid_t 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>

int main() {
        printf("Luodaan taustaprosessi\n");
        pid_t 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.