Doubt about the pipe (p) command and access to p

-1

I am currently working on a project based on multi-tasking. What I do is create a child process with the fork () command and in this process use the execl command to start an executable. The idea is that the executable can transmit information to the parent process through the use of read and write. As a means to pass information I wanted to create a stack using the pipe (p) command. Both are from c ++.

The problem is that I do not know how to share the vector p [2], so I can include it both in the code that reads, where I will declare it initially, and to include it in my executable code so do not mistake me.

In the file where I declare the forks, I have created the variable int p [2], and at its vex I have done pipe (p). Now, I need access to the p, to be able to communicate through the pipe.

I had thought about using extern int p, but it gives me an error since I can not do the extern of a pointer. Does anyone have any idea about how to share this vector? Thanks in advance.

Sorry, this would be a simplified test of the code that I'm going to use and that has the problem.

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

int main(){
 int p[2];
 char c[10];
 char skinprof[8];
 char periprof[8];
 char ef_yel_lig_ver[8];
 char ef_inter_ver[8];
 char ef_yel_lig_el[8];
 char ef_inter_el[8];
 char send="Lu";


 pipe(p);
 if(fork()){
 execl("Location of file", (char *) NULL);

 }
 else{
read(p[0],skinprof,7);
write(p[1],send,2);
read(p[0],periprof,7);
write(p[1],send,2);
read(p[0],ef_yel_lig_el,7);
write(p[1],send,2);
read(p[0], ef_inter_ver,7);
write(p[1],send,2);
read(p[0],ef_yel_lig_el,7);
write(p[1],send,2);
read(p[0],ef_inter_el,7);
write(p[1],send,2);
}
 printf("\n Los valores recibidos son: %s, %s, %s, %s, %s, %s ", skinprof,    periprof, ef_yel_lig_ver, ef_inter_ver, ef_yel_lig_el, ef_inter_el);
 return 0;
}

On the other hand, in the execl, I call a GUI that I created with wxWidgets and that I want to make the communication between the GUI and this program through the pipe. Thank you very much for the help in advance.

    
asked by sebs 03.05.2018 в 19:57
source

1 answer

2

As I understand, you have two programs in C. Let's call the first "producer.c" (I'm going to assume that you write a data in the pipeline) and the second "consumer.c" (I'm going to assume that you read a data from the pipe, process it in some way, for example, add 1, and write it again in the pipeline, where the producer reads it from). I understand that you compile both to generate executables productor and consumidor , respectively. The productor after starting and creating the pipe, makes fork() and exec() to load consumidor . Right?

In that case, obviously you can not from consumidor access the variable p created in productor , because it is a variable of a different process. It will be useless to declare it as extern . When you make fork() , the created child does have access (for now) to the variable p , since it is an identical copy of the parent, including that variable that had already been initialized. But at the moment you use exec() , the image of the child is destroyed (and with it the variable p ) to be replaced by the loaded image of the disk, consumidor .

Possible solutions:

  • Use a named pipe instead of a unnamed pipe . Named pipes are created by calling mknod() . These pipes appear as a file in the file system (in the folder of your choice). Although the variable to access it is different in the producer and the consumer, if both open the same "file" ( named pipe ) they can write and read from it to communicate.
  • After creating the child with fork() and before running exec() , redirect the standard input and output of the child to point to the pipe that you had created in the father. Then you make the exec() to load the consumidor . Everything that consumidor reads from its standard input, it will actually be reading from the pipe, and everything you type in its standard output will be actually writing it in the pipeline. The descriptors of the standard input and output are 0 and 1 respectively. You do not need the variable p .
  • Example of the first approach

    productor.c

    #include<stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    
    #define NOMBRE_TUBERIA "/tmp/tuberia"
    
    int main()
    {
      int tuberia;
      char resultado[2];
    
      // El padre comienza creando la tuberia (la borra antes por si ya existiera)
      unlink(NOMBRE_TUBERIA);
      tuberia = mknod(NOMBRE_TUBERIA, S_IRUSR| S_IWUSR|S_IFIFO, 0);
      if (tuberia<0) {
          perror("mknod");
          exit(2);
      }
      // Ahora lanzará al hijo
      if (fork()==0) {
          execl("./consumidor", "consumidor", NULL);
      }
      // El padre abre la tubería para leer y escribir
      tuberia = open(NOMBRE_TUBERIA, O_RDWR);
      if (tuberia<0) {
          perror("open");
          exit(2);
      }
      // Escribe un dato en la tuberia
      printf("Enviando un 5\n");
      write(tuberia, "5", 1);
      // Esperamos para leer la respuesta del hijo
      sleep(1);
      printf("Esperando respuesta\n");
      read(tuberia, resultado, 1);
      resultado[1]=0; // Añadir terminador
      printf("Resultado: %s\n", resultado);
      return 0;
    }
    

    consumidor.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    
    #define NOMBRE_TUBERIA "/tmp/tuberia"
    
    int main()
    {
      int tuberia;
      char resultado[2];
      int dato;
    
      // El hijo no crea la tubería (ya la creó el padre)
      // Simplemente la abre para leer y escribir
      tuberia = open(NOMBRE_TUBERIA, O_RDWR);
      if (tuberia<0) {
          perror("open");
          exit(2);
      }
      // Leemos un dato, y lo convertimos a entero
      read(tuberia, resultado, 1);
      resultado[1]=0; // Añadir terminador
      dato = atoi(resultado);
      dato++;
      // Convertimos a cadena el resultado y la escribimos en la tubería
      sprintf(resultado, "%d", dato);
      write(tuberia, resultado, 1);
      return 0;
    }
    

    Example of the second approach

    This is about using unnamed pipes, which are the ones created with pipe() . The problem is that the pipe is unidirectional. You can use it to send things from the producer to the consumer or vice versa, but not both at the same time. To have bidirectional communication, you need two pipes, which complicates the producer a bit:

    productor.c

    #include<stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    
    int main()
    {
      int p_escribir[2];  // Hacen falta dos tuberias, una para enviar cosas al consumidor
      int p_leer[2];      // la otra para recibir resultados
      char resultado[2];
    
      pipe(p_escribir);
      pipe(p_leer);
      // Ahora lanzará al hijo
      if (fork()==0) {
          // el hijo, antes de cambiarse por el consumidor, redirige su
          // entrada y salida estándar
          dup2(p_escribir[0],0 ); // La entrada estándar será el pipe donde escriba el padre
          dup2(p_leer[1], 1); // La salida estándar será el pipe de donde lea el padre
          // Despues deben cerrarse todos los pipes
          close(p_escribir[0]);
          close(p_escribir[1]);
          close(p_leer[0]);
          close(p_leer[1]);
          // Ahora cambiamos el código del hijo, cargando el consumidor
          execl("./consumidor", "consumidor", NULL);
      }
      // El padre sigue por aqui
      // Ha de cerrar los extremos del pipe que usa el hijo
      close(p_escribir[0]);
      close(p_leer[1]);
      // Escribe un dato en la tuberia
      printf("Enviando un 5\n");
      write(p_escribir[1], "5", 1);
      // Esperamos para leer la respuesta del hijo
      sleep(1);
      printf("Esperando respuesta\n");
      read(p_leer[0], resultado, 1);
      resultado[1]=0; // Añadir terminador
      printf("Resultado: %s\n", resultado);
      return 0;
    }
    

    consumidor.c

    The consumer, on the other hand, is very simple, since he does not know anything about the father's machinations. It is limited to reading from its standard input and writing to its standard output.

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <stdlib.h>
    
    int main()
    {
      char resultado[2];
      int dato;
    
      // El hijo simplemente usa su entrada/salida estándar,
      // pues ya las tiene conectadas a la tuberia
    
      // Leemos un dato de la entrada estándar (0), y lo convertimos a entero
      read(0, resultado, 1);
      resultado[1]=0; // Añadir terminador
      dato = atoi(resultado);
      dato++;
      // Convertimos a cadena el resultado y la escribimos en la salida estándar (1)
      sprintf(resultado, "%d", dato);
      write(1, resultado, 1);
      return 0;
    }
    

    Result

    Either approach produces the same result. The father, after throwing the consumer, writes a 5 in the pipe, waits a second and reads the pipeline showing the result (which has been put there by the consumer). This would be seen in the shell :

    $ ./productor
    Enviando un 5
    Esperando respuesta
    Resultado: 6
    
        
    answered by 03.05.2018 / 20:36
    source