Ero sivun ”Fork()” versioiden välillä
(toiseenkin esimerkkiin source-tagit) |
(→Esimerkki: ANSI C standardi) |
||
Rivi 17: | Rivi 17: | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#include <sys/types.h> | |||
int main() { | int main() { | ||
pid_t pid; | |||
printf("Luodaan taustaprosessi\n"); | printf("Luodaan taustaprosessi\n"); | ||
pid = fork(); | |||
if (pid==0) /* Lapsiprosessille pid näkyy nollana */ | if (pid==0) /* Lapsiprosessille pid näkyy nollana */ | ||
printf("Olen lapsiprosessi\n"); | printf("Olen lapsiprosessi\n"); |
Versio 15. lokakuuta 2016 kello 23.39
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>
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.