Premisa: Escriba un programa para consultar al usuario para dos cadenas de entrada. Cada cadena de entrada debe ser un comando Unix, con argumentos permitidos. Por ejemplo, la entrada 1 podría ser ls -l
y la entrada 2 podría ser more
. El programa creará una tubería y dos procesos secundarios. El primer proceso secundario ejecutará el comando especificado en la primera entrada. Saldrá a la tubería en lugar de la salida estándar. El segundo proceso secundario ejecutará el comando especificado en la segunda entrada. Tomará su entrada de la tubería en lugar de la entrada estándar. El proceso principal esperará a que completen sus dos hijos, y luego todo se repetirá. La ejecución se detendrá cuando se ingrese el símbolo '@' como primer comando. Aquí está el código que tengo:Tuberías y procesos
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){
/* Program Termination Symbol */
const char terminate = '@';
/* String delimiter */
const char delimiter = ' ';
/* Pipe file ID's */
int fileID[2];
/* Parent ID's */
int pid1, pid2;
/* String token */
char * token, * token2;
/* User input */
char * user_input, line[100];
user_input = (char *) malloc(100);
/* Unix Commands */
char * command1[10], *command2[10];
for (int i=0; i<10; i++)
{
command1[i] = (char *)malloc(100*sizeof(char));
command2[i] = (char *)malloc(100*sizeof(char));
}
/* Begin main program logic */
printf("Please enter the first command: \n");
user_input = gets(line);
while (user_input[0] != terminate)
{
token = (char *) malloc(100*sizeof(char));
for (int i=0; i<10; i++)
{
if (i == 0)
{
token = strtok(user_input, &delimiter);
} else {
token = strtok(NULL, &delimiter);
}
if (token != NULL)
{
strcpy(command1[i], token);
} else {
command1[i] = 0;
}
}
printf("Please enter the second command: \n");
user_input = gets(line);
token2 = (char *) malloc(100*sizeof(char));
for (int i=0; i<10; i++)
{
if (i == 0)
{
token2 = strtok(user_input, &delimiter);
} else {
token2 = strtok(NULL, &delimiter);
}
if (token2 != NULL)
{
strcpy(command2[i], token2);
} else {
command2[i] = 0;
}
}
/* Pipe and execute user commands */
/* Create pipe */
pipe(fileID);
/* Create child processes */
pid1 = fork();
if (pid1 != 0)
{
pid2 = fork();
}
/* First child process */
if (pid1 == 0)
{
dup2(fileID[1], 1);
execvp(command1[0], command1);
}
/* Second child process */
if (pid2 == 0)
{
dup2(fileID[0], 0);
execvp(command2[0], command2);
}
/* Wait for children to terminate */
wait(&pid1);
wait(&pid2);
/* Repeat */
printf("Please enter the first command: \n");
user_input = gets(line);
}
return 0;
}
El problema que me encuentro es con mi espera. Si tengo ambas cosas, lo cual tendría sentido para mí (una espera por niño), entonces el programa se congela después de ejecutar la primera tubería. Si elimino la segunda espera, el programa comenzará de nuevo su ciclo, pero no aceptará la entrada del teclado que no sea enter, y producirá una segfault. Entonces, con ambas esperas, la entrada y la salida es ...
Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
... y luego se bloquea. Si elimino la segunda espera, la entrada/salida es ...
Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
Please enter the first command:
(I hit enter, nothing else will work)
Segmentation fault
¿Alguien tiene alguna sugerencia? Está claramente relacionado con esperar en los dos procesos, pero no sé cómo manejarlo.
Este programa ahora es 100% funcional, ¡muchas gracias por su ayuda, a todos! El desbordamiento de la pila ha sido uno de los mejores recursos en Internet. Muchas gracias a todos por tomarse el tiempo para revisar mi código y darme sus sugerencias.
Solo tiene que esperar al niño al final de la tubería. –
@PeterRitchie Tenga en cuenta que la etiqueta de tarea ha quedado obsoleta (lea la descripción). Gracias. – Tim