Pipes foram uns dos primeiros mecanismos de IPC e fornecem uma das formas mais simples para a comunicação entre processos.
Pipes permitem a comunicação num estilo standard (Producer - Consumer):
- O producer escreve para uma ponta do pipe (the write-end);
- O consumer lê pela outra ponta do pipe (the read-end);
Os pipes são unidirecionais, apenas permitem comunicação em um sentido.
Se for necessária comunicação nos dois sentidos, devem ser usados dois pipes, onde cada pipe envia dados em direções diferentes.
Pipes podem ser construídos no terminal
usando o caractere |
:
ls | sort
cat fich.txt | grep xpto
Em sistemas Unix, os pipes são criados pela System Call pipe()
;
int pipe(int fd[2]);
A System Call pipe()
cria um novo pipe e inicia fd[2] com os seguintes descritores:
- fd[0] é o read-end do pipe.
- fd[1] é o write-end do pipe.
Em Unix os pipes são tratados como um tipo de ficheiro especial, o que permite o acesso aos mesmos usando as comuns System Calls read()
e write()
;
Um pipe não pode ser acedido fora do processo que o criou.
- Tipicamente, um processo pai cria um pipe e usa-o para comunicar com o processo filho que é criado via
fork()
; - Como o pipe é considerado um tipo de ficheiro especial, o processo filho herda o pipe do processo pai.
Depois de um fork, podemos decidir a direção do fluxo dos dados dentro do pipe.
-
Num pipe de Pai-Filho, o progenitor fecha a extremidade de leitura (read-end) do pipe fd[0] e o filho fecha a extremidade de escrita (write-end) fd[1].
-
A Leitura a partir de um pipe aberto (i.e pelo menos um dos processos tem fd[1] aberto) bloqueia-o enquanto este se encontra vazio.
#define BUFFER_SIZE 25
#define READ_END 0
#define WRITE_END 1
int main(void){
char write_msg[BUFFER_SIZE] = "Folks";
char read_msg[BUFFER_SIZE];
int fd[2];
pid_t pid;
/* Criação do pipe */
if(pipe(fd) == -1){
perror("Creating pipe");
return 1;
}
/* Fork do processo filho */
pid = fork();
if (pid < 0){ /* Ocorreu um erro */
perror("Creating child");
return 1;
}
if (pid > 0) {
/* Processo pai */
/* Fecho do fim inutilizado do pipe */
close(fd[READ_END]);
/* Escrita no pipe */
write(fd[WRITE_END]), write_msg , strlen(write_msg)+1);
/* Fecho do final escrito do pipe */
close(fd[WRITE_END]);
}
else{
/* Processo filho */
/* Fecho do fim inutilizado do pipe */
close(fd[WRITE_END]);
/* Leitura do pipe */
read(fd[READ_END], read_msg, BUFFER_SIZE);
/* Fecho do final escrito do pipe */
close(fd[READ_END]);
}
return 0;
}