Creación y duplicación de procesos en C (Parte II) – Linux

| 2013-08-23 | No hay comentarios »

Repaso de las funciones:

Fork y wait:

Para crear nuevos procesos, el UNIX dispone únicamente de una llamada al sistema, fork, sin ningún tipo de parámetros. Su prototipo es

int fork();

Al llamar a esta función se crea un nuevo proceso (proceso hijo), idéntico en código y datos al proceso que ha realizado la llamada (proceso padre). Los espacios de memoria del padre y el hijo son disjuntos, por lo que el proceso hijo es una copia idéntica del padre que a partir de ese momento sigue su vida separada, sin afectar a la memoria del padre; y viceversa.

Siendo más concretos, las variables del proceso padre son inicialmente las mismas que las del hijo. Pero si cualquiera de los dos procesos altera una variable, el cambio sólo repercute en su copia local. Padre e hijo no comparten memoria.

El punto del programa donde el proceso hijo comienza su ejecución es justo en el retorno de la función fork, al igual que ocurre con el padre.

Si el proceso hijo fuera un mero clon del padre, ambos ejecutarían las mismas instrucciones, lo que en la mayoría de los casos no tiene mucha utilidad. El UNIX permite distinguir si se es el proceso padre o el hijo por medio del valor de retorno de fork. Esta función devuelve un cero al proceso hijo, y el identificador de proceso (PID) del hijo al proceso padre. Como se garantiza que el PID siempre es no nulo, basta aplicar un if para determinar quién es el padre y quién el hijo para así ejecutar distinto código.

Ejemplo:


//Llamada a librerías
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

//Función principal
main(int argc, char **argv[])
{
 //Declaramos variables
 int status,pid;

 //Si fork() es igual a 0 entonces es hijo
 if((pid=fork()==0))
 {
 printf("\nSoy hijo, mi pid es: %d\n",getpid());
 printf("\nMi padre tiene el pid: %d\n",getppid());
 //La función sleep solamente lo que hace es esperar 10 segundos para luego continuar
 sleep(10);
 }
 //Sino entonces es Padre
 else
 {
 //La función sleep solamente lo que hace es esperar 10 segundos para luego continuar
 sleep(10);
 printf("\nSoy Padre, mi pid es: %d\n",getpid());
 printf("\ntengo que esperar a mi hijo: %d\n",pid);
 //Con el wait esperamos a que el hijo finalice.
 wait(&status);
 printf("\nmi hijo termino con un estado: %d\n",status);
 }
}

La función system():

La forma más sencilla de invocar una orden UNIX desde un programa en C es mediante la función system, que toma como único parámetro la orden que quieren ejecutar. Reconoce redirecciones, expresiones regulares, conductos (pipes), etc. Por ejemplo, la línea

system("ls -l /usr/include/*.h >pepe.txt")

ejecuta la cadena pasada como parámetro tal y como si la hubiéramos tecleado desde la consola. La función system se limita a lanzar un shell hijo pasándole como parámetro de entrada la cadena suministrada en la función.

La forma de más bajo nivel para ejecutar una orden consiste en lanzar a ejecución el programa deseado mediante alguna de las llamadas al sistema que empiezan por exec. Existen varias modalidades que difieren en la forma de pasar los parámetros al programa (aunque realmente se trata de una sola llamada al sistema UNIX).

Ejemplo:


//Llamada a librerías
//Con system() nuestro programa consigue detener su ejecución para llamar a un comando de la shell (“/bin/sh” típicamente) y retornar cuando éste haya acabado.
#include<stdio.h>
#include<stdlib.h>

//Función principal
main(int argc, char **argv[])
{

printf("hola\n");
//Mostrar un ls -l del directorio actual
system("ls -l");
//Esperar 10 segundos
sleep(10);
//Mostrar la lista de procesos que contengan system y direccionarlo a salida.txt
system("ps | grep system > salida.txt");
printf("chau\n");
//Mostramos el contenido de salida.txt
system("cat salida.txt");

}

Las llamadas exec:

El sistema operativo UNIX ofrece una llamada al sistema llamada ‘exec’ para lanzar a ejecución un programa, almacenado en forma de fichero. Aunque en el fondo sólo existe una llamada, las bibliotecas estándares del C disponen de varias funciones, todas comenzando por ‘exec’ que se diferencian en la manera en que se pasan parámetros al programa.

La versión típica cuando se conoce a priori el número de argumentos que se van a entregar al programa se denomina execl. Su sintaxis es

int execl ( char* fichero, char* arg0, char* arg1, ... , 0 );

Ejemplo:


//Llamada a librerías
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

//Función principal
main(int argc, char **argv[])
{
 //Declaramos variables
 int status,pid;


 //Si fork() es igual a 0 entonces es hijo
 if((pid=fork()==0))
 {
 printf("hola soy hijo\n");
 //Cabe destacar que una llamada a execl reemplaza el proceso actual, es por eso que lo cree dentro de un proceso hijo
 execl("/bin/ls","ls","-l",0);
 }
 //Sino entonces es Padre
 else
 {
 wait(&status);
 printf("soy el padre, se termino el listado");
 }
}

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.




SEGUÍNOS EN FACEBOOK


GITHUB