Ero sivun ”Fork()” versioiden välillä
(→Esimerkki: source tagit) |
(toiseenkin esimerkkiin source-tagit) |
||
Rivi 2: | Rivi 2: | ||
==Prototyyppi== | ==Prototyyppi== | ||
pid_t fork() | pid_t fork() | ||
===Paluuarvo=== | ===Paluuarvo=== | ||
Rivi 42: | Rivi 42: | ||
===[[demoni|Taustaprosessin]] luominen=== | ===[[demoni|Taustaprosessin]] luominen=== | ||
fork-funktion ajavan ohjelman toinen osa jää taustalle ja alkuperäinen ohjelma voidaan sammuttaa. Esimerkkikoodi: | fork-funktion ajavan ohjelman toinen osa jää taustalle ja alkuperäinen ohjelma voidaan sammuttaa. Esimerkkikoodi: | ||
< | <source lang="c"> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
Rivi 56: | Rivi 56: | ||
return 0; | return 0; | ||
} | } | ||
</ | </source> | ||
Tallennetaan koodi tiedostoon <tt>taustaprosessi.c</tt>, käännetään se komennolla <tt>gcc taustaprosessi.c -o taustaprosessi</tt> ja ajetaan se (<tt>./taustaprosessi</tt>). Tuloste on seuraavanlainen: | Tallennetaan koodi tiedostoon <tt>taustaprosessi.c</tt>, käännetään se komennolla <tt>gcc taustaprosessi.c -o taustaprosessi</tt> ja ajetaan se (<tt>./taustaprosessi</tt>). Tuloste on seuraavanlainen: | ||
$ ./taustaprosessi | $ ./taustaprosessi |
Versio 18. elokuuta 2016 kello 22.47
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.