Preparação do Ambiente
Para realizar os exercícios a seguir, é necessário um sistema Linux com o compilador gcc instalado. No Ubuntu, pode-se instalar as ferramentas esssenciais com:
sudo apt update
sudo apt install build-essential
Exercício 1: Combinação de Dois Arquivos em um Único Destino
Este programa lê dois arquivos de entrada e grava seus conteúdos sequencialmente em um arquivo de saída, inserindo uma quebra de linha entre eles.
Código-fonte
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define BUFFER_SIZE 1024
void copiar_conteudo(int origem, int destino) {
char buffer[BUFFER_SIZE];
ssize_t bytes_lidos;
while ((bytes_lidos = read(origem, buffer, BUFFER_SIZE)) > 0) {
write(destino, buffer, bytes_lidos);
}
}
int main(int argc, char **argv) {
int descritor_entrada1, descritor_entrada2, descritor_saida;
const char separador = '\n';
if (argc != 4) {
fprintf(stderr, "Uso: %s <arquivo_origem_1> <arquivo_origem_2> <arquivo_destino>\n", argv[0]);
return 1;
}
descritor_entrada1 = open(argv[1], O_RDONLY);
if (descritor_entrada1 < 0) {
perror("Erro ao abrir primeiro arquivo");
return 1;
}
descritor_entrada2 = open(argv[2], O_RDONLY);
if (descritor_entrada2 < 0) {
perror("Erro ao abrir segundo arquivo");
close(descritor_entrada1);
return 1;
}
descritor_saida = open(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (descritor_saida < 0) {
perror("Erro ao criar arquivo de saida");
close(descritor_entrada1);
close(descritor_entrada2);
return 1;
}
copiar_conteudo(descritor_entrada1, descritor_saida);
write(descritor_saida, &separador, 1);
copiar_conteudo(descritor_entrada2, descritor_saida);
close(descritor_entrada1);
close(descritor_entrada2);
close(descritor_saida);
return 0;
}
Compilação e Execução
gcc combinador.c -o combinador
echo "Conteudo do primeiro arquivo" > entrada1.txt
echo "Conteudo do segundo arquivo" > entrada2.txt
./combinador entrada1.txt entrada2.txt resultado.txt
cat resultado.txt
Resultado esperado:
Conteudo do primeiro arquivo
Conteudo do segundo arquivo
Exercício 2: Execução de Comandos com fork e exec
Este exemplo cria um processo filho que substitui sua imagem por um novo programa utilizando execl, enquanto o processo pai aguarda sua conclusão.
Código-fonte
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
pid_t processo_filho;
processo_filho = fork();
if (processo_filho == 0) {
execlp("ls", "ls", "-l", NULL);
perror("Falha na execucao de execlp");
exit(EXIT_FAILURE);
} else if (processo_filho > 0) {
wait(NULL);
printf("Processo filho finalizado\n");
exit(EXIT_SUCCESS);
} else {
perror("Erro ao criar processo com fork");
exit(EXIT_FAILURE);
}
}
Compilação e Execução
gcc exec_comando.c -o exec_comando
./exec_comando
O programa listará os arquivos do diretório atual em formato longo e exibirá a mensagem de conclusão.
Exercício 3: Registro de Identificadores de Processo em Arquivo
Este programa demonstra a criação de processos com fork, onde tanto o processo pai quanto o filho gravam suas informações de PID em um arquivo compartilhado.
Código-fonte
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#define ARQUIVO_DADOS "dados_processo"
void registrar_info(int fd, const char *mensagem) {
write(fd, mensagem, strlen(mensagem));
}
int main(void) {
int descritor_arquivo;
pid_t pid_filho;
char texto_pai[80];
char texto_filho[80];
descritor_arquivo = open(ARQUIVO_DADOS, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (descritor_arquivo < 0) {
perror("Nao foi possivel abrir o arquivo");
exit(EXIT_FAILURE);
}
pid_filho = fork();
if (pid_filho == 0) {
printf("=== Processo Filho ===\n");
printf("PID: %d\n", getpid());
printf("PID do Pai: %d\n", getppid());
snprintf(texto_filho, sizeof(texto_filho), "Escrito pelo filho (PID %d)\n", getpid());
registrar_info(descritor_arquivo, texto_filho);
close(descritor_arquivo);
exit(EXIT_SUCCESS);
} else if (pid_filho > 0) {
printf("=== Processo Pai ===\n");
printf("PID: %d\n", getpid());
printf("PID do Filho: %d\n", pid_filho);
snprintf(texto_pai, sizeof(texto_pai), "Escrito pelo pai (PID %d)\n", getpid());
registrar_info(descritor_arquivo, texto_pai);
close(descritor_arquivo);
wait(NULL);
exit(EXIT_SUCCESS);
} else {
perror("Falha no fork");
close(descritor_arquivo);
exit(EXIT_FAILURE);
}
}
Compilação e Execução
gcc registro_pid.c -o registro_pid
./registro_pid
cat dados_processo
Saída no temrinal:
=== Processo Pai ===
PID: 1024
PID do Filho: 1025
=== Processo Filho ===
PID: 1025
PID do Pai: 1024
Conteúdo do arquivo dados_processo:
Escrito pelo pai (PID 1024)
Escrito pelo filho (PID 1025)