[Capitulo II] Procesos

Iniciado por [L]ord [R]NA, 6 Octubre 2010, 08:19 AM

0 Miembros y 1 Visitante están viendo este tema.

[L]ord [R]NA

Procesos

   Un programa en ejecucion recibe el nombre de proceso. Estos estan gestionados por el sistema operativo. Un proceso esta conformado por las instrucciones que van a ser ejecutadas por el microprocesador, el estado de ejecucion en un momento especifico, la memoria de trabajo para el proceso y otra informacion que requiera el sistema operativo.

   En los sistemas operativos basados en Linux cada proceso es identificado por un unico ID llamado Process ID(pid). Los Process IDs son numeros de 32bits asignados secuencialmente por Linux cada vez que un nuevo proceso es creado. Aparte de todo esto, cada proceso tiene un proceso padre, exceptuando el proceso 'init', cuando nos refiramos desde un proceso hijo hacia un proceso padre nos referiremos con la abreviatura ppid(Parent Process ID).

   Para referirnos al ID de un proceso utilizaremos el tipo 'pid_t' el cual esta definido en el archivo cabecera '<sys/types.h>'. Una pequeña aclaracion, el tipo de dato pid_t es simplemente un tipo 'signed int', utilizar el tipo 'pid_t' o 'signed int' no hara ningun cambio pero para facilidad de lectura de tu codigo por otras personas es preferible utilizar 'pid_t' cuando te refieras a un Process ID.

Obteniendo nuestro Process ID


   En algunos casos necesitaremos obtener nuestro Process ID, para verificarlo en una lista, para pasarlo a otro proceso, etc. Para obtener dicho Process ID se nos ha dotado de dos funciones getpid(),para obtener nuestro propio Process ID, y getppid(),para obtener el Process ID del proceso padre, dichas funciones se encuentran en el archivo cabecera 'unistd.h' el cual es el archivo que nos da acceso a las API del Sistema Operativo POSIX (Portable Operative System Interface for uniX).
   
   Ninguna de las funciones vistas anteriormente reciben un parametro y como valor de retorno devuelven un pid_t, el cual dependera de la funcion que ha sido llamada.

pid_t getpid (void)
pid_t getppid (void)



   Veamos un pequeño ejemplo del uso de estas funciones:


#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
pid_t currentpid, parentpid;
currentpid = getpid();
parentpid = getppid();
printf("El proceso %i es padre del proceso %i \n",parentpid,currentpid);
return 0;
}


Como vemos si ejecutamos varias veces el mismo programa en la misma consola, el valor del Process ID del proceso padre no varia debido a que la consola es el proceso padre.

Creando un Proceso.

Existen dos tecnicas comunes para crear un proceso, la primera es utilizando 'system()', es sencilla de utilizar pero esta se debe de utilizar con cierta precaucion debido a que es ineficiente y es considerada como un riesgo de seguridad.La segunda es utilizando fork() o exec(), esta es mas compleja pero nos otorga flexibilidad, velocidad y seguridad.

Utilizando system():


int system (const char *string)

Hay que tomar en consideracion 2 valores de retorno, devolvera '127' si la ejecucion en la consola falla, en caso de otro error el valor de retorno sera -1. Aparte de estos valores, system() mostrara en pantalla en caso de ser posible el proceso o comando ejecutado.

#include <stdio.h>

int main()
{
printf("%i \n",system("dir"));
return 0;
}


para mas informacion:
man 3 system

Utilizando fork() y exec():


pid_t fork(void)

La funcion fork() crea un proceso hijo identico al proceso padre, la unica diferencia entre ellos es el PID y la direccion de memoria fisica en la RAM. En los actuales Sistemas Operativos las direcciones de las variables en memoria no corresponden a la verdadera memoria fisica en hardware. Las direcciones estan administradas por direcciones virtuales en el Sistema Operativo por esta razon en el proceso padre y el proceso hijo incluso cuando tienen la misma direccion virtual de memoria, la direccion fisica es diferente.

La funcion fork() devuelve en el proceso padre el pid del proceso hijo, mientras que en el proceso hijo devuelve 0.


#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
pid_t proc;
int status,value=0;

if(proc=fork())
{
printf("Process: %i %x\n",getpid(),&value);
waitpid(proc,&status,0);
printf("%i \n",value);
return 0;
}

else
{
printf("Process: %i %i %x\n",getpid(),getppid(),&value);
value = 2000;
return 0;
}
}


para mas informacion:
man 2 fork

La familia exec()



int execl(const char *path, const char *arg, ...)
int execlp(const char *file, const char *arg, ...)
int execle(const char *path, const char *arg, ..., char * const envp[])
int execv(const char *path, char *const argv[])
int execvp(const char *file, char *const argv[])


Las funciones exec() remplazan el programa en ejecucion por otro programa dentro de un proceso. Inmediatamente se hace una llamada exec() el proceso en ejecucion se detiene y el nuevo programa inicia la ejecucion asumiendo que la llamada no tenga un error. Debido a que exec() remplaza el programa actual en ejecucion, este no retornara el control a menos que suceda un error o nuevo programa en ejecucion termine.

Veamos un pequeño ejemplo para utilizar fork() y exec() en el mismo programa:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
pid_t proc;
int status,value=0;

if(proc=fork())
{
waitpid(proc,&status,0);
printf("Clear Used \n");
return 0;
}

else
{
execvp("clear",argv);
return 0;
}
}


Terminando un proceso


   Normalmente un proceso termina de dos formas. o llamando una funcion de salida, o por el valor de retorno. Cada proceso tiene un valor de salida. Cada proceso tiene un codigo de salida y ese codigo es devuelto a su proceso padre, entiendase por codigo el valor de retorno.

   En algunos casos necesitaremos cerrar un proceso, debido a que ya no lo necesitemos, para estos casos existe la funcion kill(). La funcion kill recibe 2 parametros. El primer parametro es el PID de un proceso o de un grupo de procesos. El segundo parametro es la señal, la cual es un valor constante.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>

int main(int argc, char *argv[])
{
pid_t proc;
int status,value=0;

if(proc=fork())
{
kill(proc,SIGTERM);
if(status==0)printf("El proceso %i se ha cerrado \n",proc);
return 0;
}

else
{
while(1)printf("KILL ME. \n");
}
}


para mas informacion sobre kill():
man 2 kill

para mas informacion sobre el valor constante de las señales:
/usr/include/bits/signum.h

Esperando la terminacion de un proceso


   Debido a que el S.O. Linux es un sistema operativo multitareas cuando trabajamos con varios procesos, por ejemplo con una llamada a fork, no existe la certeza de cual proceso terminara primero. En algunas ocasiones necesitaremos esperar el valor de retorno de un proceso hijo o de multiples procesos hijos que habran realizado diferentes instrucciones y para estos casos existe la funcion wait().

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
pid_t proc;
int status,value=0;

if(proc=fork())
{
waitpid(proc,&status,0);
if(status==0)printf("El proceso %i ha terminado con exito \n",proc);
return 0;
}

else
{
return 0;
}
}


para mas informacion:man 2 wait

Foxy Rider

#1
CitarLos Process IDs son numeros de 16bits asignados secuencialmente por Linux cada vez que un nuevo proceso es creado

CitarPara referirnos al ID de un proceso utilizaremos el tipo 'pid_t' el cual esta definido en el archivo cabecera '<sys/types.h>'. Una pequeña aclaracion, el tipo de dato pid_t es simplemente un tipo 'signed int', utilizar el tipo 'pid_t' o 'signed int' no hara ningun cambio pero para facilidad de lectura de tu codigo por otras personas es preferible utilizar 'pid_t' cuando te refieras a un Process ID.

16 bits -> short
int -> 32 bits


Saludos.

[L]ord [R]NA

:xD sabia que se me habia escapado algo... ya esta editado.

Khronos14

Hola Lord R.N.A., está muy bien el curso, de hecho tenía ganas de empezar a trabajar de lleno con la API de Linux. Pero me surgió una duda:

La API de Windows tiene 2 métodos para trabajar con ficheros, por ejemplo: CreateFileA y CreateFileW, pero.. ¿Cómo hace Linux para trabajar con ficheros que tienen una ruta en formato UNICODE o UTF-8?¿Emplea un sistema parecido al de Windows o trata las rutas como char y luego hace la conversión a wchar_t?

Saludos.

[L]ord [R]NA

para lo que pides esta fwprintf().

Info:
man 3 fwprintf

Foxy Rider


/* En algun lugar de sys/types.h */
typedef __pid_t pid_t; /* process id */

/* En algun lugar de sys/_types.h */
typedef __int32_t __pid_t; /* process [group] */


Esto en FreeBSD, en Linux es igual (un int), pero con un código más feito ...

Saludos.

...condoscojo...

Aunque el prodecimiento es simple no dejaria de interesarles a quienes empiecen en este lenguage.

saludos Lord R.N.A.