#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