A chamada de sistema exec é usada para executar um arquivo que está residindo em um processo ativo. Quando exec é chamado, o arquivo executável anterior é substituído e um novo arquivo é executado.
Mais precisamente, podemos dizer que usar a chamada de sistema exec substituirá o arquivo ou programa antigo do processo por um novo arquivo ou programa. Todo o conteúdo do processo é substituído por um novo programa.
O segmento de dados do usuário que executa a chamada de sistema exec () é substituído pelo arquivo de dados cujo nome é fornecido no argumento ao chamar exec ().
O novo programa é carregado no mesmo espaço de processo. O processo atual acaba de ser transformado em um novo processo e, portanto, o ID do processo PID não é alterado, isso é porque não estamos criando um novo processo, estamos apenas substituindo um processo por outro processo em exec.
Se o processo atualmente em execução contiver mais de uma thread, todas as threads serão encerradas e a nova imagem do processo será carregada e executada. Não há funções destruidoras que encerram threads do processo atual.
O PID do processo não é alterado, mas os dados, código, pilha, heap, etc. do processo são alterados e substituídos por aqueles do processo recém-carregado. O novo processo é executado a partir do ponto de entrada.
A chamada do sistema Exec é uma coleção de funções e, na linguagem de programação C, os nomes padrão para essas funções são os seguintes:
- execl
- execle
- execlp
- execv
- execvo
- execvp
Deve-se notar aqui que essas funções têm a mesma base exec seguido por uma ou mais letras. Eles são explicados abaixo:
e: É uma matriz de ponteiros que aponta para variáveis de ambiente e é passada explicitamente para o processo recém-carregado.
eu: l é para os argumentos de linha de comando passados uma lista para a função
p: p é a variável de ambiente do caminho que ajuda a encontrar o arquivo passado como um argumento a ser carregado no processo.
v: v é para os argumentos da linha de comando. Eles são passados como uma matriz de ponteiros para a função.
Por que exec é usado?
exec é usado quando o usuário deseja lançar um novo arquivo ou programa no mesmo processo.
Trabalho interno do executivo
Considere os seguintes pontos para entender o funcionamento do executivo:
- A imagem do processo atual é substituída por uma nova imagem do processo.
- A nova imagem do processo é aquela que você passou como argumento exec
- O processo atualmente em execução foi encerrado
- A nova imagem de processo tem o mesmo ID de processo, mesmo ambiente e mesmo descritor de arquivo (porque o processo não é substituído a imagem do processo é substituída)
- A estatística da CPU e a memória virtual são afetadas. O mapeamento da memória virtual da imagem do processo atual é substituído pela memória virtual da nova imagem do processo.
Sintaxes das funções da família exec:
A seguir estão as sintaxes para cada função de exec:
int execl (const char * path, const char * arg, ...)int execlp (arquivo const char *, const char * arg,…)
int execle (const char * path, const char * arg,…, char * const envp [])
int execv (const char * path, const char * argv [])
int execvp (arquivo const char *, const char * argv [])
int execvpe (const char * arquivo, const char * argv [], char * const envp [])
Descrição:
O tipo de retorno dessas funções é Int. Quando a imagem do processo é substituída com sucesso, nada é retornado para a função de chamada porque o processo que o chamou não está mais em execução. Mas se houver algum erro -1 será retornado. Se ocorrer algum erro, um errno está definido.
Na sintaxe:
- caminho é usado para especificar o nome do caminho completo do arquivo que deve ser executado.
- arg o argumento foi aprovado. Na verdade é o nome do arquivo que será executado no processo. Na maioria das vezes, o valor de arg e caminho é o mesmo.
- const char * arg nas funções execl (), execlp () e execle () é considerado como arg0, arg1, arg2,…, argn. É basicamente uma lista de ponteiros para strings terminadas em nulos. Aqui, o primeiro argumento aponta para o nome do arquivo que será executado conforme descrito no ponto 2.
- envp é um array que contém ponteiros que apontam para as variáveis de ambiente.
- Arquivo é usado para especificar o nome do caminho que irá identificar o caminho do novo arquivo de imagem do processo.
- As funções de exec chamam que terminam com e são usados para mudar o ambiente para a nova imagem do processo. Essas funções passam a lista de configuração de ambiente usando o argumento envp. Este argumento é uma matriz de caracteres que aponta para uma string terminada em nulo e define a variável de ambiente.
Para usar as funções da família exec, você precisa incluir o seguinte arquivo de cabeçalho em seu programa C:
#incluirExemplo 1: usando a chamada de sistema exec no programa C
Considere o seguinte exemplo no qual usamos a chamada de sistema exec em programação C no Linux, Ubuntu: Temos dois arquivos c aqui exemplo.ce olá.c:
exemplo.c
CÓDIGO:
#incluir#incluir
#incluir
int main (int argc, char * argv [])
printf ("PID de exemplo.c =% d \ n ", getpid ());
char * args [] = "Olá", "C", "Programação", NULL;
execv ("./ hello ", args);
printf ("Voltar ao exemplo.c ");
return 0;
Olá.c
CÓDIGO:
#incluir#incluir
#incluir
int main (int argc, char * argv [])
printf ("Estamos em Olá.c \ n ");
printf ("PID de olá.c =% d \ n ", getpid ());
return 0;
RESULTADO:
PID de exemplo.c = 4733Estamos em olá.c
PID de olá.c = 4733
No exemplo acima, temos um exemplo.arquivo c e olá.arquivo c. No exemplo .arquivo c primeiro imprimimos o ID do processo atual (exemplo de arquivo.c está sendo executado no processo atual). Então, na próxima linha, nós criamos uma matriz de ponteiros de caracteres. O último elemento desta matriz deve ser NULL como ponto final.
Então nós usamos a função execv () que leva o nome do arquivo e o array de ponteiro de caractere como seu argumento. Deve-se notar aqui que usamos ./ com o nome do arquivo, especifica o caminho do arquivo. Como o arquivo está na pasta onde exemplo.c reside, então não há necessidade de especificar o caminho completo.
Quando a função execv () é chamada, nossa imagem de processo será substituída agora o arquivo de exemplo.c não está no processo, mas o arquivo Olá.c está em processo. Pode-se ver que o ID do processo é o mesmo se olá.c é uma imagem de processo ou exemplo.c é a imagem do processo porque o processo é o mesmo e a imagem do processo é apenas substituída.
Então temos outra coisa a notar aqui que é a instrução printf () depois que execv () não é executado. Isso ocorre porque o controle nunca é retornado à imagem do processo antigo, uma vez que a nova imagem do processo o substitui. O controle só volta a chamar a função quando a substituição da imagem do processo é malsucedida. (O valor de retorno é -1 neste caso).
Diferença entre chamadas de sistema fork () e exec ():
A chamada de sistema fork () é usada para criar uma cópia exata de um processo em execução e a cópia criada é o processo filho e o processo em execução é o processo pai. Enquanto a chamada de sistema exec () é usada para substituir uma imagem de processo por uma nova imagem de processo. Portanto, não há conceito de processos pai e filho na chamada de sistema exec ().
Na chamada do sistema fork () os processos pai e filho são executados ao mesmo tempo. Mas na chamada do sistema exec (), se a substituição da imagem do processo for bem-sucedida, o controle não retorna para onde a função exec foi chamada, em vez disso, ele executará o novo processo. O controle só será transferido de volta se houver algum erro.
Exemplo 2: Combinando chamadas de sistema fork () e exec ()
Considere o exemplo a seguir, no qual usamos as chamadas de sistema fork () e exec () no mesmo programa:
exemplo.c
CÓDIGO:
#incluir#incluir
#incluir
int main (int argc, char * argv [])
printf ("PID de exemplo.c =% d \ n ", getpid ());
pid_t p;
p = garfo ();
if (p == - 1)
printf ("Ocorreu um erro ao chamar fork ()");
if (p == 0)
printf ("Estamos no processo filho \ n");
printf ("Chamando oi.c do processo filho \ n ");
char * args [] = "Olá", "C", "Programação", NULL;
execv ("./ hello ", args);
senão
printf ("Estamos no processo pai");
return 0;
Olá.c:
CÓDIGO:
#incluir#incluir
#incluir
int main (int argc, char * argv [])
printf ("Estamos em Olá.c \ n ");
printf ("PID de olá.c =% d \ n ", getpid ());
return 0;
RESULTADO:
PID de exemplo.c = 4790Estamos em processo pai
Estamos em processo infantil
Chamando olá.c do processo filho
Estamos em olá.c
PID de olá.c = 4791
Neste exemplo, usamos a chamada de sistema fork (). Quando o processo filho for criado, 0 será atribuído a p e então passaremos para o processo filho. Agora o bloco de instruções com if (p == 0) será executado. Uma mensagem é exibida e nós usamos a chamada de sistema execv () e a imagem do processo filho atual que é um exemplo.c será substituído por olá.c. Antes da chamada de execv (), os processos filho e pai eram os mesmos.
Pode ser visto que o PID de exemplo.ce olá.c é diferente agora. Isso ocorre porque exemplo.c é a imagem do processo pai e olá.c é a imagem do processo filho.