You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Prosessinhallinta

Prosessinhallinnan systeemikutsut:

  • uuden prosessin luonti fork()
  • prosessin koodinvaihto exec()
  • prosessin lopettaminen exit()
  • prosessin päättymisen odotus wait(), waitpid()

    Prosession luonti

Prosessi luodaan funktiolla pid_t *fork(void);, joka palauttaa kutsuvalle prosessille lapsiprosessin numeron ja lapsiprosessille 0. fork()-kutsun tuloksena syntyy uusi prosessi, joka on 'klooni' äitiprosessista.

  • yhteinen koodi
  • samat muuttujien arvot
  • samat prosessinkuvaajan perustiedot
  • yhteiset avoimet tiedostot

Kummallakin on kuitenkin:

  • oma data-alue
  • oma prosessinkuvaaja

fork()-kutsun jälkeen ei voi olla varma siitä kumpi prosessi (äiti vai lapsi) jatkaa aiemmin suoritustaan. Jos järjestys tärkeää, on ohjelmoitava itse synkronointi ( Esim 1.#include < sys/types.h >
#include < unistd.h >

int glob = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";

int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;

var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
perror("write error");
printf("before fork\n"); /* we don't flush stdout */

if ( (pid = fork()) < 0)
perror("fork error");
else if (pid == 0)

Unknown macro: { /* child */ glob++; /* modify variables */ var++; }

else
sleep(2); /* parent */

printf("pid=%d,glob=%d,var=%d\n",getpid(), glob, var);
exit(0);
}

Lapsiprosessi luodaan, kun:

  • halutaan suorittaa äiti- ja lapsiprosessissa erillinen osa samassa tiedostossa olevasta koodista. Esim. verkkosovelluksissa on tavallista, että palvelija luo lapsiprosessin antamaan palvelua ja jää itse odottamaan uusia palvelupyyntöjä.
  • halutaan suorittaa kokonaan toinen ohjelma. Tällöin fork()-kutsun jälkeen on lapsiprosessissa myös exec()-kutsu, eli se vaihtaa suoritettavaa koodia. Esim. komentotulkit käyttävät tätä menetelmää.
    Lapsi perii äidiltä kaikki avoimet tiedostokuvaajat. Sekä äiti että lapsi käyttävät yhteistä avoimet tiedostot taulun alkiota niillä on yhteinen luku / kirjoituspositio.

    4.2 Prosession päättyminen

Prosessin suoritus päättyy normaalisti, kun suoritetaan:

  • funktiossa main() funktio return(status)
  • funktio exit(status) tai
  • funktio _exit(status)

exit() kutsuu funktiolla atexit() rekisteröityjä funktioita ja purkaa stdio:n puskurit (vrt. funktio flush()). _exit() hoitelee Unix-spesifiset lopputoimet Prosessin suoritus voi päättyä myös 'epänormaalisti', kun kutsutaan funktiota abort() tai prosessi saa signaalin, johon se ei varautunut tai ei voi varautua. Epänormaaleissa päättymisissä generoi ydin paluuarvon.

Unix-spesifisiin lopputoimiin kuuluu tiedostojen sulkeminen, muistitilan vapauttaminen sekä äitiprosessin signalointi, mutta prosessinkuvaaja jää vielä olemaan ("zombie"). Koska paluuarvon välittäminen äitiprosessille ja laskutustietojen kokoaminen on vielä kesken.

Jos äitiprosessi on päättynyt ennen lapsiprosessia, merkitsee ydin zombien äidiksi prosessin 1 (init). Se kokoaa laskutustiedot ja vapauttaa prosessinkuvaajan.

Kun prosessi päättyy, saa äiti aina signaalin SIGCHLD. Oletusarvo on, että äiti ei välitä tästä signaalista. Äiti voi pysähtyä odottamaan lapsen päättymistä funktioon wait() tai waitpid():#include < sys/types.h >
#include < sys/wait.h >

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
Palauttaa: päättyneen prosessin pid,
parametrissa statloc on päättyneen lapsen status
Jos lapsiprosessi on jo päättynyt, pääsee äitiprosessi heti jatkamaan. Funktiolla waitpid() voi määrätä odotettavaksi jonkin tietyn prosessin päättymistä, kun taas funktiolla wait() odotetaan minkä tahansa lapsen päättymistä.

  • pid == -1 odota mitä tahansa lapsiprosessia
  • pid > 0 odota lasta, jolla ko. pid
  • pid == 0 odota mitä tahansa äidin kanssa samaan prosessiryhmän kuuluvaa lasta
  • pid < -1 odota prosessiryhmään |pid| kuuluvaa prosessia

    4.3 Prosessin koodin vaihto

Prosessi vaihtaa suoritettavaa koodia funktiolla exec(). Siitä on kuusi erilaista muotoa, jotka eroavat komentoriviargumenttien ja ympäristömuuttujien välityksessä. Koodia etsitään annetun polkunimen perusteella funktioissa execl(), execv(), execle(), execve() tai tiedostonimen perusteella ympäristömuuttujassa PATH luetelluista hakemistoista fuktioissa execlp() tai execvp();.

Koodille voi välittää komentoriviargumentteja joko listana (execl()) tai vektorina (execv()). Koodille voi välittää edellisten lisäksi myös haluamansa ympäristömuuttujat aina vektorina execle() tai execve() tai äidin ympäristömuuttujat periytyvät lapselle sellaisenaan environ-muuttujasta.#include < unistd.h >

int execl(const char pathname, const char *arg0, ... / NULL */);
int execv(const char *pathname, char *const argv[]);

int execle(const char pathname, const char *arg0, ... / NULL, char *const envp[] */);
int execve(const char *pathname, char *const argv[], char *const envp[]);

int execlp(const char filename, const char *arg0, ... / NULL */)
int execvp(const char *filename, char *const argv[]);

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

char *env_init[] =

Unknown macro: { "USER=unknown", "PATH=/tmp", NULL }

;

int
main(void)
{
pid_t pid;

if ( (pid = fork()) < 0)
perror("fork error");
else if (pid == 0)

Unknown macro: { /* specify pathname, specify environment */ if (execle("/bin", "echo", "myarg1", "MY ARG2", (char *) 0, env_init) < 0) perror("execle error"); }

if (waitpid(pid, NULL, 0) < 0)
perror("wait error");

if ( (pid = fork()) < 0)
perror("fork error");
else if (pid == 0)

Unknown macro: { /* specify filename, inherit environment */ if (execlp("echo", "echo", "only 1 arg", (char *) 0) < 0) perror("execlp error"); }

exit(0);
}

  • No labels
You must log in to comment.