Fork, exec, wait e exit chamada de sistema explicada no Linux
A sequência de instruções e dados que podem ser executados uma única vez, várias vezes ou simultaneamente são chamados de programas. E o processo é a execução de tais programas. Portanto, esses processos podem executar muitos programas. No mesmo processo, o sistema operacional pode carregar programas diferentes. Estados de processos reutilizados, como diretórios atuais, privilégios, identificadores de arquivos, etc., são herdados pelos novos programas. Essas coisas são feitas no mesmo nível com syscalls como fork(), exec(), wait() e exit().
Neste artigo, discutiremos os syscalls fork(), exec(), wait() e exit() do Linux em detalhes com exemplos e casos de uso.
garfo()
O fork() é um dos syscalls muito especial e útil em sistemas Linux/Unix. É usado por processos para criar processos que são cópias de si mesmos. Com a ajuda dessas chamadas de sistema, o processo filho pode ser criado pelo processo pai. Até que o processo filho seja executado completamente, o processo pai fica suspenso.
Alguns dos pontos importantes sobre fork() são os seguintes.
- O pai obterá o ID do processo filho com valor diferente de zero.
- O valor Zero é retornado ao filho.
- Se houver algum erro de sistema ou hardware durante a criação do filho, -1 será retornado para fork().
- Com o ID de processo exclusivo obtido pelo processo filho, ele não corresponde ao ID de nenhum grupo de processos existente.
Para elaborar mais sobre fork(), vamos dar um exemplo que esclarece o conceito fork().
sudo vim fork.c
Aqui está o código para copiar/colar:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid==0)
{
printf("It is the child process and pid is %d\n",getpid());
exit(0);
}
else if(pid > 0)
{
printf("It is the parent process and pid is %d\n",getpid());
}
else
{
printf("Error while forking\n");
exit(EXIT_FAILURE);
}
return 0;
}
Saída:
$make fork
E executando o script, obtemos o resultado conforme a imagem abaixo.
./fork
executivo()
O exec() é uma chamada de sistema executada substituindo a imagem do processo atual pela nova imagem do processo. No entanto, o processo original permanece como um novo processo, mas o novo processo substitui os dados principais, os dados da pilha, etc. Ele executa o programa a partir do ponto de entrada, carregando o programa no espaço de processo atual.
Para elaborar mais, vamos dar um exemplo conforme mostrado abaixo.
sudo vim exec.c
E aqui está o código:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
main(void) {
pid_t pid = 0;
int status;
pid = fork();
if (pid == 0) {
printf("I am the child.");
execl("/bin/ls", "ls", "-l", "/home/ubuntu/", (char *) 0);
perror("In exec(): ");
}
if (pid > 0) {
printf("I am the parent, and the child is %d.\n", pid);
pid = wait(&status);
printf("End of process %d: ", pid);
if (WIFEXITED(status)) {
printf("The process ended with exit(%d).\n", WEXITSTATUS(status));
}
if (WIFSIGNALED(status)) {
printf("The process ended with kill -%d.\n", WTERMSIG(status));
}
}
if (pid < 0) {
perror("In fork():");
}
exit(0);
}
Saída:
make exec
E executando o script, obtemos o resultado conforme a imagem abaixo.
./exec
espere()
Como no caso de uma bifurcação, os processos filhos são criados e executados, mas o processo pai é suspenso até que o processo filho seja executado. Neste caso, uma chamada de sistema wait() é ativada automaticamente devido à suspensão do processo pai. Depois que o processo filho termina a execução, o processo pai ganha o controle novamente.
Para elaborar mais sobre wait(), vamos dar um exemplo que esclarece a chamada de sistema wait().
sudo vim wait.c
Aqui está o exemplo de código:
#include<stdio.h> // printf()
#include<stdlib.h> // exit()
#include<sys/types.h> // pid_t
#include<sys/wait.h> // wait()
#include<unistd.h> // fork
int main(int argc, char **argv)
{
pid_t pid;
pid = fork();
if(pid==0)
{
printf("It is the child process and pid is %d\n",getpid());
int i=0;
for(i=0;i<8;i++)
{
printf("%d\n",i);
}
exit(0);
}
else if(pid > 0)
{
printf("It is the parent process and pid is %d\n",getpid());
int status;
wait(&status);
printf("Child is reaped\n");
}
else
{
printf("Error in forking..\n");
exit(EXIT_FAILURE);
}
return 0;
}
Saída:
make wait
E executando o script, obtemos o resultado conforme a imagem abaixo.
./wait
saída()
O exit() é uma função ou uma das chamadas do sistema usada para encerrar o processo. Esta chamada de sistema define que a execução do thread é concluída especialmente no caso de um ambiente multithread. Para referência futura, o status do processo é capturado.
Após o uso da chamada de sistema exit(), todos os recursos utilizados no processo são recuperados pelo sistema operacional e então encerram o processo. A chamada do sistema Exit() é equivalente a exit().
Sinopse
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void _Exit(int status);
Você pode ver o uso da função exit() nos exemplos acima de fork(), wait(). O uso da chamada de sistema exit() é feito para encerrar o processo.
Conclusão
Neste artigo, aprendemos detalhadamente as chamadas de sistema fork(), exec(), wait() e exit() com alguns exemplos. Para obter mais detalhes, tente executar os programas usando essas chamadas de sistema e veja o resultado. Obrigado!