C/Visual C - Pipes y stdout/stdin

 
Vista:

Pipes y stdout/stdin

Publicado por Javi (1 intervención) el 24/10/2007 17:05:57
Necesito crear 2 pipes para poder comunicar 3 comandos, la salida del primer comandoo a la entrada del segundo y a su vez esta salida a la entrada del ultimo,
Al hacerlo para 2 procesos, anda bien, pero cuando agrego el código para correr el ultimo comando (proceso padre) se queda esperando la stdin.
Supongo que tiene que ver que estoy redireccionando la stdout dos veces.. Alguna idea?

Gracias,

int main(int argc, char *argv[])
{
int firstPipe[2];
int secondPipe[2];

int ilStdinOriginal=dup(STDIN_FILENO);
int ilSrdoutOriginal=dup(STDOUT_FILENO);

if (pipe(firstPipe) < 0)
{
return -1;
}

if (pipe(secondPipe) < 0)
{
return -1;
}

if (0==fork())
{
// Child 1

close(firstPipe[0]);
close(secondPipe[1]);
dup2(firstPipe[1],STDOUT_FILENO);
close(firstPipe[1]);

if (system("ls -lai")==-1)
{
// Restore stdout
dup2(ilSrdoutOriginal,STDOUT_FILENO);
printf("Unable to run command );
exit(-1);
}


} else {


if (0==fork())
{
// Child 2

close(firstPipe[1]);
close(secondPipe[0]);

dup2(firstPipe[0],STDIN_FILENO);
close(firstPipe[0]);

close(secondPipe[0]);
dup2(secondPipe[1],STDOUT_FILENO);
close(secondPipe[1]);


if (system("grep 12")==-1)
{
// Restore stdout
dup2(ilSrdoutOriginal,STDOUT_FILENO);
printf("Unable to run command );
exit(-1);
}
} else {
// Father

close(secondPipe[1]);
dup2(secondPipe[0],STDIN_FILENO);
close(secondPipe[0]);

if (system("wc")==-1)
{

// Restore stdout
dup2(ilSrdoutOriginal,STDOUT_FILENO);
printf("Unable to run command );
exit(-1);
}
}
}
}
}
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Pipes y stdout/stdin

Publicado por Tom (619 intervenciones) el 25/10/2007 17:44:19
Pues a simple vista debería funcionar ... lo estoy probando y también me hace cosas raras.
Creo que el problema podría estar relacionado con el hecho de que system() también abre otro pipe ...

Además hay otro problemilla ... debes cerrar (close()) el canal de salida de "ls -lai" para que "wc" se entere de que su entrada ha terminado.

En este ejemplo (dos procesos) se observa algo que quizás sea lo que t e está pasando.

Compila, ejecuta y cuando termine (aparece OK y una línea en blanco) escribe directamente una orden del shell (por ejemplo, ps). Verás que es el shell el que se queda esperando y no el programa.


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* */
int main(int argc, char *argv[]) {
int pfd[2];
int sstdin = STDIN_FILENO;
int sstdout = STDOUT_FILENO;
pid_t cpid;

if(pipe(pfd) < 0) {
perror("pipe");
exit(1);
}
cpid = fork();
if(cpid < 0) {
perror("fork");
exit(1);
}
if(cpid) {
int st;
// Parent Proc.
close(pfd[0]);
dup2(pfd[1], STDOUT_FILENO);
system("ls");
close(STDOUT_FILENO);
//fprintf(stderr, "Terminando Padre (Hijo ya acabó)\n");
} else {
// Child Proc.
close(pfd[1]);
dup2(pfd[0], STDIN_FILENO);
system("cat -n");
//close(STDIN_FILENO);
}
//wait(NULL);
dup2(sstdout, STDOUT_FILENO);
dup2(sstdin, STDIN_FILENO);
write(sstdout, "OK\n", 3);
exit(0);
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Pipes y stdout/stdin

Publicado por Tom (619 intervenciones) el 25/10/2007 19:03:46
Vale, error de principiante, que nadie pierda tiempo para hacer funcionar mi ejemplo.
.
Mi fallo estaba en no hacer dup(STDOUT_...) para guardar su descriptor. Mi ejemplo ya funciona, voy a intentar hacerlo con tres procesos ....
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Pipes y stdout/stdin

Publicado por Marianela (1 intervención) el 20/09/2009 15:38:35
Ha pasado el tiempo ,pero hoy me encuentro con este tema
me gustaría saber como hacerlo para n procesos recibidas por consola
gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Buf

Publicado por Tom (619 intervenciones) el 26/10/2007 11:59:32
Vaya lío. Tal y como pensaba, el uso de system() (que hace fork()) está complicando las cosas.

Utiliza exec(), y no olvides cerrar la salida standard de un comando para que el siguiente en el pipe sepa que debe finalizar.

Este ejemplo funciona:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* */
int main(int argc, char *argv[]) {
int p0[2],
p1[2];

pipe(p0);
launch("ls", STDIN_FILENO, p0[1]);
pipe(p1);
launch("nl", p0[0], p1[1]);
launch("wc", p1[0], STDOUT_FILENO);

}
/* */
int launch(char proc[], int fin, int fout) {
int pid = fork();

if(!pid) {
if(fin != STDIN_FILENO) {
dup2(fin, STDIN_FILENO);
}
if(fout != STDOUT_FILENO) {
dup2(fout, STDOUT_FILENO);
}
execlp(proc, proc, NULL);
//system(proc);
} else {
waitpid(pid, NULL, 0);
close(fout);
}
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Solución 1

Publicado por Tom (619 intervenciones) el 29/10/2007 20:46:02
Una solución muy próxima a la que tú intentabas implementar.
Observa que, para hacer "ls | cat -n | wc" se lanzan los procesos (con fork()/exec()) así:

wc es padre de cat es padre de ls

Lo suyo sería hacerlo usando una función recursiva (para que se pudieran lanzar un número cualquiera de procesos, y no solo 3), pero parece un poco lioso.

Además, hay otra aproximación (de la que pondré un ejemplo si consigo hacerla funcionar :-)) que es la que usa bash: todos los procesos son hijos de bash (un fork()/exec() por cada uno) y él coordina los pipes.

/* */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
int p0[2];

pipe(p0);

int pid = fork();

if(pid == 0) {
int p1[2];

pipe(p1);

int ppid = fork();

if(ppid == 0) {
/* Hijo de Hijo */
close(p0[0]);
close(p0[1]);
close(p1[0]);
dup2(p1[1], STDOUT_FILENO);
close(p1[1]);
execlp("ls", "ls", NULL);
perror("ls");
_exit(1);
}
if(ppid > 0) {
/* Hijo */
close(p0[0]);
close(p1[1]);
dup2(p1[0], STDIN_FILENO);
dup2(p0[1], STDOUT_FILENO);
close(p1[0]);
close(p0[1]);
execlp("cat", "cat", "-n", NULL);
perror("cat");
_exit(1);
}
}
if(pid > 0) {
/* Padre */
dup2(p0[0], STDIN_FILENO);
close(p0[0]);
close(p0[1]);
execlp("wc", "wc", NULL);
perror("wc");
exit(1);
}
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Solución 2

Publicado por Tom (619 intervenciones) el 30/10/2007 10:57:28
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
int i = 1;

if(argc > 1) {
if(argc > 2) {
int pipes[argc - 2][2];
int procs[argc - 2];
pipes[0][0] = STDIN_FILENO;
pipes[0][1] = STDOUT_FILENO;

for(i = 1; i < (argc - 1); i++) {
pipe(pipes[i]);
procs[i] = fork();
if(procs[i] == 0) {
dup2(pipes[i - 1][0], STDIN_FILENO);
dup2(pipes[i][1], STDOUT_FILENO);
closepipes(pipes, i);
execlp(argv[i], argv[i], NULL);
perror("execlp");
_exit(1);
}
}
dup2(pipes[i - 1][0], STDIN_FILENO);
closepipes(pipes, i - 1);
}
execlp(argv[i], argv[i], NULL);
}
exit(1);
}

/* */
int closepipes(int pipes[][2], int i) {
int j;

for(j = 1; j <= i; j++) {
close(pipes[j][0]);
close(pipes[j][1]);
}
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar