next up previous
Next: Problema com os buffers Up: As primitivas envolvendo processos Previous: As primitivas envolvendo processos


A primitiva fork()

       #include <unistd.h>

       pid_t fork(void)       /* criação de um processo filho */
       pid_t vfork(void);     /* funciona como um alias de fork */

Valor de retorno: 0 para o processo filho, e o identificador do processo filho para o processo pai; -1 em caso de erro (o sistema suporta a criação de um número limitado de processos).

Esta primitiva é a única chamada de sistema que possibilita a criação de um processo em UNIX. Os processos pai e filho partilham o mesmo código. O segmento de dados do usuário do novo processo (filho) é uma cópia exata do segmento correspondente ao processo antigo (pai). Por outro lado, a cópia do segmento de dados do filho do sistema pode diferir do segmento do pai em alguns atributos específicos (como por exemplo, o pid, o tempo de execução, etc.). Os filhos herdam uma duplicata de todos os descritores dos arquivos abertos do pai (se o filho fecha um deles, a cópia do pai não será modificada). Mais ainda, os ponteiros para os arquivos associados são divididos (se o filho movimenta o ponteiro dentro de um arquivo, a próxima manipulação do pai será feita a partir desta nova posição do ponteiro). Esta noção é muito importante para a implementação dos pipes (tubos) entre processos.

Exemplo:

                 /* arquivo test_fork1.c */    

/* Descritores herdados pelos processos filhos */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

int main()
{
int pid ;
int fd ; /* descritor de arquivo associado ao arquivo agenda */
char *telephone ;
int r ; /* retorno de read */
int i ;   
char c ;
     printf("Oi, eu sou o processo %d\n",getpid()) ;
     printf("Por favor, envie-me o seu numero de telefone\n") ;
     printf("E o 123456789 ? Ok, ja anotei na minha agenda\n") ;
     if((fd=open("agenda",O_CREAT|O_RDWR|O_TRUNC,S_IRWXU))==-1) 
     {
          perror("impossivel de abrir a agenda") ;
          exit(-1) ;
     }
     telephone="123456789" ; 
     if(write(fd,telephone,9)==-1)
     {
          perror("impossivel de escrever na agenda") ;
          exit(-1) ;
     }
     printf("Enfim, acabei de anotar e estou fechando a agenda\n") ;
     close(fd) ;
     printf("O que ? Eu me enganei ? O que foi que eu anotei ?\n") ;
     printf("\tO pai reabre sua agenda\n") ;
                  if((fd=open("agenda",O_RDONLY,S_IRWXU))==-1)      {
          perror("impossivel de abrir a agenda") ;
          exit(-1) ;
     }
     printf("\tNesse instante, o pai gera um filho\n") ;
     pid=fork() ;
     if(pid==-1) /* erro */
     {
          perror("impossivel de criar um filho") ;
          exit(-1) ;
     }
     else if(pid==0) /* filho */
     {
          sleep(1) ; /* o filho dorme para agrupar as mensagens */
          printf("\t\tOi, sou eu %d\n",getpid()) ;
          printf("\t\tVoces sabem, eu tambem sei ler\n") ;
          printf("\tO filho entao comeca a ler a agenda\n") ;
          for(i=1;i<=5;i++)  
          {
               if(read(fd,&c,1)==-1)
               {
                    perror("impossivel de ler a agenda") ;
                    exit(-1) ;
               }
               printf("\t\tEu li um %c\n",c) ;
          }
          printf("\tMinha agenda ! Diz o pai\n") ;
          printf("\te supreso o filho fecha a agenda...\n") ;
          close(fd) ;
          sleep(3) ;
          printf("\tO filho entao se suicida de desgosto!\n") ;
          exit(1) ;
     }
     else /* pai */
     {
          printf("De fato, eu apresento a voces meu filho %d\n",pid) ;
          sleep(2) ; 
          printf("Oh Deus ! Eu nao tenho mais nada a fazer\n");
          printf("Ah-ha, mas eu ainda posso ler minha agenda\n") ;   
          while((r=read(fd,&c,1))!=0)
          {
                
               if(r==-1)
               {
                    perror("impossivel de ler a agenda") ;
                    exit(-1) ;
               }
               printf("%c",c) ;
          }
          printf("\n") ;
          printf("ENFIM ! Mas onde estao todos ?\n") ;
          sleep(3) ;
          close(fd) ;
     }
     exit(0);
}

Resultado da Execução:

euler:~> test_fork1
Oi, eu sou o processo 28339
Por favor, envie-me o seu numero de telefone
E o 123456789 ? Ok, ja anotei na minha agenda
Enfim, acabei de anotar e estou fechando a agenda
O que ? Eu me enganei ? O que foi que eu anotei ?
        O pai reabre sua agenda
        Nesse instante, o pai gera um filho
                Oi, sou eu 28340
                Voces sabem, eu tambem sei ler
        O filho entao comeca a ler a agenda
                Eu li um 1
                Eu li um 2
                Eu li um 3
                Eu li um 4
                Eu li um 5
        Minha agenda ! Diz o pai
        e supreso o filho fecha a agenda...
        O filho entao se suicida de desgosto!
Oi, eu sou o processo 28339
Por favor, envie-me o seu numero de telefone
E o 123456789 ? Ok, ja anotei na minha agenda
Enfim, acabei de anotar e estou fechando a agenda
O que ? Eu me enganei ? O que foi que eu anotei ?
        O pai reabre sua agenda
        Nesse instante, o pai gera um filho
De fato, eu apresento a voces meu filho 28340
Oh Deus ! Eu nao tenho mais nada a fazer
Ah-ha, mas eu ainda posso ler minha agenda
6789
ENFIM ! Mas onde estao todos ?

Observação:

Três pontos principais devem ser observados no exemplo anterior:

  1. O filho herda os descritores ''abertos'' do pai - uma vez que o filho pode ler a agenda sem que seja necessário abri-la.
  2. O filho pode fechar um descritor aberto pelo pai, sendo que esse descritor continuará aberto para o pai.
  3. Os dois processos compartilham do mesmo ponteiro sobre o arquivo duplicado na chamada da primitiva fork! Note que quando o pai vai ler o arquivo, ele vai se movimentar dentro desse arquivo da mesma forma que seu filho.

Comportamento da saída no console:

Note que se o pai e o filho vivem, uma interrupção de teclado (via CTRL-c) irá destruir os dois processos. Entretanto, se um filho vive enquanto seu pai está morto, uma interrupção pode não matá-lo. Veja o exemplo de programa a seguir.

Exemplo:

                 
               /* arquivo test_fork2.c */

/* Testa as reacoes do console quando um pai 
 * morre e o filho continua vivo */

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
int pid ;
   printf("Eu sou o pai %d e eu vou criar um filho \n",getpid()) ;
   pid=fork() ; /* criacao do filho */
   if(pid==-1) /* erro */
   {
      perror("impossivel de criar um filho\n") ;
   }    
   else if(pid==0) /* acoes do filho */
   {
      printf("\tOi, eu sou o processo %d, o filho\n",getpid()) ;
      printf("\tO dia esta otimo hoje, nao acha?\n") ;
      printf("\tBom, desse jeito vou acabar me instalando para sempre\n");
      printf("\tOu melhor, assim espero!\n") ;
      for(;;) ; /* o filho se bloqueia num loop infinito */
   }
   else /* acoes do pai */
   {
       sleep(1) ; /* para separar bem as saidas do pai e do filho */
       printf("As luzes comecaram a se apagar para mim, %d\n",getpid()) ;
       printf("Minha hora chegou : adeus, %d, meu filho\n",pid) ;
       /* e o pai morre de causas naturais */ 
    }
    exit(0);
}

Resultado da Execução:

euler:~> test_fork2
Eu sou o pai 28637 e eu vou criar um filho 
        Oi, eu sou o processo 28638, o filho
        O dia esta otimo hoje, nao acha?
        Bom, desse jeito vou acabar me instalando para sempre
        Ou melhor, assim espero!
As luzes comecaram a se apagar para mim, 28637
Minha hora chegou : adeus, 28638, meu filho

Se o comando shell ps é executado no console, a seguinte saída é obtida:

euler:~> ps
  PID TTY STAT  TIME COMMAND
28300  ?  S    0:00 -tcsh 
28638  ?  R    0:04 test_fork2 
28639  ?  R    0:00 ps

Note que o filho permanece rodando! Tente interrompê-lo via teclado usando CTRL-c ou CTRL-d. Ele não quer morrer, não é verdade? Tente matá-lo diretamente com um sinal direto através do comando shell kill.

kill -9 <pid>

No caso do exemplo anterior, deveria ser feito:

kill -9 28638

Desta vez estamos certos que Jason morreu! ?

euler:~> kill -9 28638
euler:~> ps
  PID TTY STAT  TIME COMMAND
28300  ?  S    0:00 -tcsh 
28666  ?  R    0:00 ps



Subsections
next up previous
Next: Problema com os buffers Up: As primitivas envolvendo processos Previous: As primitivas envolvendo processos
Celso Alberto Saibel Santos 2000-11-14