#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:
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