Criação e rescisão de processos
Até agora sabemos que sempre que executamos um programa, um processo é criado e seria encerrado após a conclusão da execução. E se precisarmos criar um processo dentro do programa e quisermos agendar uma tarefa diferente para ele. Isso pode ser alcançado? Sim, obviamente por meio da criação do processo. Claro, depois que o trabalho for concluído, ele será encerrado automaticamente ou você pode encerrá-lo conforme necessário.
A criação do processo é alcançada através do fork() system call. O processo recém-criado é chamado de processo filho e o processo que o iniciou (ou o processo quando a execução é iniciada) é chamado de processo pai. Após a chamada de sistema fork (), agora temos dois processos - processos pai e filho. Como diferenciá-los? Muito simples, é por meio de seus valores de retorno.
Após a criação do processo filho, vamos ver os detalhes da chamada do sistema fork ().
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
Cria o processo filho. Após essa chamada, há dois processos, o existente é chamado de processo pai e o recém-criado é chamado de processo filho.
A chamada do sistema fork () retorna um dos três valores -
Valor negativo para indicar um erro, ou seja, falha na criação do processo filho.
Retorna zero para o processo filho.
Retorna um valor positivo para o processo pai. Este valor é o ID do processo do processo filho recém-criado.
Vamos considerar um programa simples.
File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
fork();
printf("Called fork() system call\n");
return 0;
}
Etapas de execução
Compilação
gcc basicfork.c -o basicfork
Execução / Saída
Called fork() system call
Called fork() system call
Note- Normalmente, após a chamada de fork (), o processo filho e o processo pai executariam tarefas diferentes. Se a mesma tarefa precisar ser executada, para cada chamada de fork () ela será executada 2 vezes n vezes, onden é o número de vezes que fork () é chamado.
No caso acima, fork () é chamado uma vez, portanto, a saída é impressa duas vezes (2 potência 1). Se fork () for chamado, digamos 3 vezes, a saída será impressa 8 vezes (2 potência 3). Se for chamado 5 vezes, ele imprimirá 32 vezes e assim por diante.
Tendo visto fork () criar o processo filho, é hora de ver os detalhes dos processos pai e filho.
Nome do arquivo: pids_after_fork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
pid_t pid, mypid, myppid;
pid = getpid();
printf("Before fork: Process id is %d\n", pid);
pid = fork();
if (pid < 0) {
perror("fork() failure\n");
return 1;
}
// Child process
if (pid == 0) {
printf("This is child process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
} else { // Parent process
sleep(2);
printf("This is parent process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
printf("Newly created process id or child pid is %d\n", pid);
}
return 0;
}
Etapas de compilação e execução
Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628
Newly created process id or child pid is 166630
Um processo pode terminar de uma das duas maneiras -
Anormalmente, ocorre na entrega de certos sinais, digamos sinal de término.
Normalmente, usando _exit () chamada de sistema (ou _Exit () chamada de sistema) ou função de biblioteca exit ().
A diferença entre _exit () e exit () é principalmente a atividade de limpeza. oexit() faz alguma limpeza antes de retornar o controle de volta ao kernel, enquanto o _exit() (ou _Exit ()) retornaria o controle de volta ao kernel imediatamente.
Considere o seguinte programa de exemplo com exit ().
Nome do arquivo: atexit_sample.c
#include <stdio.h>
#include <stdlib.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
exit (0);
}
Etapas de compilação e execução
Hello, World!
Called cleanup function - exitfunc()
Considere o seguinte programa de exemplo com _exit ().
Nome do arquivo: at_exit_sample.c
#include <stdio.h>
#include <unistd.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
_exit (0);
}
Etapas de compilação e execução
Hello, World!