Problemas Tema 4: Gestión de procesos en Unix

Anuncio
Problemas Tema 4: Gestión de procesos en Unix
Problema 4.1.
Feu un programa que escrigui un missatge amb la seva identificació (per exemple, “El meu pid és
%d\n”,getpid ()), que executi un fork i, per tant, creï un procés fill, i finalment que torni a escriure
la seva identificació. Per què es produeix la duplicació del segon missatge?
Problema 4.2.
Sabeu que la crida fork torna el pid del procés fill al procés pare; i torna un zero al procés fill. Modifiqueu el programa anterior de forma que pare i fill escriguin el segon missatge diferent (per exemple, “PARE: el meu pid és ...” i “FILL: el meu pid és ...”)
Problema 4.3.
El procés fill creat per un fork no comparteix les variables globals amb el pare; únicament hereda
els seus valors. Escriviu un programa en C en el qual el fill, abans d’acabar, esperi que el pare modifiqui una variable global. Veure que el pare acaba, però el fill no. (comproveu-ho amb la comanda
ps)
Problema 4.4.
Modifiqueu el programa anterior per veure que els valors de les variables locals (que són a la pila)
també s’hereden, però les pròpies variables tampoc es comparteixen.
Problema 4.5.
Escriviu un programa en el qual es creï una pipe i un procés fill. El pare ha d’escriure una línia de
text a la pipe i el fill l’ha de llegir. Recordeu que cada procés ha de tancar el descriptor que no faci
servir.
Problema 4.6.
Escriviu un programa que obri un fitxer per escriptura i creï un procés fill. El fill fa avançar el punter
de lectura / escriptura. El pare espera 10 segons i escriu al fitxer. Comproveu que l’escriptura del
pare s’ha fet a la posició que havia fixat el fill.
Problema 4.7.
Creeu un procés fill que escrigui el seu identificador i el del seu pare. El pare, també escriurà la
identificació del fill que ha creat i la seva pròpia. Després, esperarà la finalització del fill. Veure que
l’estat que rep el pare és, en part, proporcionat per l’argument que el fill dòna a la funció exit().
Problema 4.8.
Feu un programa per veure qui adopta els processos que es queden sense pares. La sortida hauria
Problemas Tema 4:Gestión de procesos en Unix
1
de ser semblant a:
Sóc el procés XXX i el meu fill és el YYY
Sóc el procés YYY i el meu pare és el XXX
El meu pare ha mort i ara el meu nou pare és el ZZZ
Quin és el procés ZZZ? Qui és el seu pare? (la crida al sistema getppid() torna l'identificador del
procés pare del procés que la invoca)
Problema 4.9. Esperar fill
Programeu una funció que rebi el pid d’un procés fill concret, esperi que aquest procés acabi i
retorni l’estat en que ha acabat (int EsperarFill(int pid)).
Problema 4.10. Esperar tots els fills
Programeu una funció que esperi a que acabin tots els fills d’un procés, retornant el nombre de fills
que tenia aquest procés (int EsperarTotsElsFills()).
Problema 4.11.
Ja coneixeu les diferències que hi ha entre un Sistema Operatiu que ofereix processos mulfi-fluxes
enfront d’un altre que ofereix processos amb un únic fluxe. Comenteu quins avantatges i quins
inconvenients suposa tenir varis fluxes per procés.
EXECUCIÓ DE PROGRAMES
Problema 4.12.
Creeu un procés fill que escrigui el seu identificador i l’identificador del seu pare. El codi d’aquest
procés estarà en un fitxer executable diferent al del pare, i s’executarà fent servir la crida execlp.
El pare, també escriurà la identificació del fill que ha creat i la seva pròpia. Després, esperarà la
finalització del fill.
Problema 4.13.
Feu un programa que rebi un argument. Aquest argument serà una cadena que representarà un
número (per exemple, 10). Primer, el programa escriu el seu identificador de procés i el número.
Si el número és més gran que zero, el programa s’executa a si mateix passant-se com a argument
el número decrementat en 1 (en el nostre exemple, 9) i en cas contrari acaba.
Problema 4.14.
Creeu n (n>2) processos fills que executin un mateix programa (que atura la seva execució durant
un cert temps, com fa la comanda sleep). Feu que el pare esperi a un fill concret usant la funció
EsperarFill(pid) programada abans.
Problema 4.15.
Escribid un programa que cree tantos hijos como se le indique en la línea de comandos. Cada uno
Problemas Tema 4:Gestión de procesos en Unix
2
de estos hijos le enviará al padre su identificador de proceso mediante una pipe (todos los hijos por
la misma pipe) y a continuación morirá. El padre escribirá en un fichero (segundo parámetro) todos
los mensajes que le lleguen.
Ejemplo: prompt% crea 15 hijos
Creará 15 hijos cuyos identificadores aparecerán en el fichero “hijos”.
Problema 4.16.
Escribid un programa que cree tantos hijos como se le indican en argv[1] (como máximo creará 10
hijos). Con cada uno de ellos deberá abrir una pipe diferente.
Una vez creados los hijos y las pipes, el proceso padre deberá abrir el fichero cuyo nombre se
le pasa en argv[2] y leerá de 10 en 10 bytes hasta que se acabe el fichero. De cada 10 bytes, el primer byte es un carácter ASCII en el rango de ’0’ a ’9’. Usando este primer carácter el proceso padre
le enviará al hijo correspondiente los bytes leidos.
Cada hijo deberá ejecutar el siguiente código:
/*fichero hijo.c*/
main (int argc,char *argv[])
{
int nb;
char b[80];
sprintf(b,”>>> %s\n”,argv[1]);
write(1,b,strlen(b));
while((nb=read(0,b,sizeof(b)))>0)
write(1,b,nb);
}
Problema 4.17. Multihead
Heu d’escriure un programa que anomenarem multihead que presenti el següent comportament:
multihead file1 N1 ... filem Nm Escriurà per la seva sortida estàndar (i en aquest ordre) les N1
primeres línies del fitxer file1, les N2 primeres línies del fitxer
file2,..., i les Nm primeres línies del fitxer filem.
Com a codi d’acabament multihead ens haurà de retornar:
• 0
Ha pogut fer la feina correctament
• 2i
El fitxer filei no existeix
• 2i+1
El fitxer filei no té Ni línies
• 1
Qualsevol altre error provocat per alguna crida al sistema
Si es detecta que algun fitxer no té el nombre de línies indicat o que no existeix, aquest programa
finalitzarà inmediatament, retornant el codi d’acabament pertinent.
Per simplificar la solució heu de fer servir el programa de sistema head que presenta el següent
comportament.
head N
Treu per la seva sortida estàndar les N primeres línies que li arriben per la seva
entrada estàndar.
Com a codi d’acabament head ens retorna:
• 0
Ha pogut realitzar la feina correctament
• 1
S’ha produit un error provocat per alguna crida al sistema
• 2
L’entrada estàndar no té N línies
Problemas Tema 4:Gestión de procesos en Unix
3
Nota: El codi d’acabament d'un procés és el paràmetre que es passa a la crida al sistema exit, i
que es obtenible pel seu procés pare amb la crida wait.
Problema 4.18.
Donats els següents programes:
Pare.c
#define NULL (char *) 0
main()
{ int
fd,fp[2],err,status,id;
char
c;
Fill.c
main()
{ char
B
while (read(0,&c,1)>0)
write(1,&c,1);
exit(0);
}
fd = open (“pp.pp”,O_RDONLY);
err = pipe(fp);
if (fd == -1)||(err==-1) exit(1);
id = fork();
switch (id) {
case 0:
c;
A
T.Fitxers oberts
close(0);
dup(fp[0]);
close(fp[0];
close(fp[1]);
execl(“fill”,fill”,NULL);
exit(1);
case -1:exit(1);
default:close(1);
dup(fp[1]);
close(fp[0]);
close(fp[1]);
count mode offset
T.Canals
punter
0
1
2
3
rw
32
B
while(read(fd,&c,1)!=0)
write(1,&c,1);
close(1);
wait(&status);
exit(0);}
figura 1
}
A la figura 1 podeu veure la disposició dels camps de les possibles estructures de dades internes
del sistema operatiu: taula de canals (una per procés) i taula de fitxers oberts (una per a tot el sistema). Aquesta taula té els camps següents: Count (nombre de descriptors de canal que apunten a
aquesta entrada de la TFO), Mode (mode en què s'ha obert el fitxer (r, w, rw)) i Offset (posició
actual d'on llegir i/o escriure dades).
3. Dibuixeu la Taula de Canals i la Taula de Fitxers Oberts al punt A. Cal que ompliu
els camps explicats a la figura 1. Suposeu que podem tenir fins a 10 canals oberts.
4. Feu el mateix que a la pregunta anterior però en el punt d’execució B, suposant que
en un moment donat tant el pare com el fill estan, simultàniament, al punt B.
5. Què fa aquest programa si l’executem des de la shell de la següent forma:
prompt% pare <in.dat >& out.dat
on “<“ indica redireccionament del canal d’entrada i “>&” el redireccionament dels canals de sortida i error?
Problemas Tema 4:Gestión de procesos en Unix
4
GESTIÓ D’EVENTS - SIGNALS
Problema 4.19.
Programeu dues rutines en C que ofereixin la funcionalitat d’unes suposades crides a sistema (que
no tenim a UNIX) aturar i engegar. Amb elles fer dos programes que rebin com a argument un pid
i aturin o engeguin el procés sol.licitat..
Problema 4.20.
Feu un programa que llegeixi una línia del terminal. Si durant un període de 10 segons no s’ha
teclejat un return, el programa ha d’acabar donant un error tal com
Error reading command input Timeout period expired
Si s'ha llegit una línia en menys de 10 segons, el programa cridarà a la rutina processar_linia(char
*).
Problema 4.21.
Escriviu un programa que rebi un argument. Considereu que aquest argument és, segur, una P o
una F. En el primer cas (P), el pare enviarà un signal SIGKILL al fill. En el segon, serà el fill qui
enviï un SIGKILL al pare. Per què el resultat de les dues execucions (amb argument P o F) és diferent ? Qui escriu el missatge killed ? Quan ?
Feu el mateix que abans, però enviant un signal diferent (per exemple, SIGINT) i fent que tant
el pare com el fill el tinguin programat.
Suggeriment: feu que el pare i el fill s’esperin uns 2 segons abans d’acabar. Així tenen temps
per rebre el signal.
Problema 4.22. Runner
Escriviu un programa (“Runner”) tal que quan rebi el signal SIGUSR1, vol dir que cal executar un
nou programa.
El nom d'aquest nou programa el llegirà per una Named Pipe. Per la Named Pipe també es reben
els noms dels fitxers que han d’actuar com a canals d'entrada i sortida estàndar.
Així, si tenim executant-se el “Runner” en background, des de csh podem fer la seqüència:
kill
echo
echo
echo
-SIGUSR1 pid
'fill' >Named_Pipe
'/dev/ttyl' >Named_Pipe
'sortida_fill' >Named_Pipe
i el resultat serà la creació d'un nou procés que executarà el programa del fitxer 'fill', amb l'entrada estàndar sobre el terminal i la sortida estàndar sobre el fitxer 'sortida_fill'.
Si els canals d'entrada o sortida especificats es corresponen a “herència”, cal que el procés fill
heredi els canals del programa “Runner”. Feu servir la rutina de llibreria de C strcmp (s1,s2), que
retorna 0 si las cadenes s1 i s2 son iguals.
Problemas Tema 4:Gestión de procesos en Unix
5
Així, el programa “Runner” tindrà el següent esquema:
/* Declaració de variables */
...
/* Rutina de tractament del signal */
...
main()
{
/* Inicialitzacions */
...
/* Esperar, per sempre, el signal SIGUSR1*/
...
}
Problema 4.23. Dos mètodes
Disposem de dos programes diferents (mètode1 i mètode2) que realitzen un mateix càlcul. Llegeixen 3 nombres de la seva entrada estàndar, i per la sortida estàndar escriuen un enter que és el
resultat del càlcul. La diferència entre aquests dos programes és el temps d’execució; per algunes
entrades el mètode1 ens donarà abans el resultat que el mètode2, però per les altres entrades serà
el mètode2 el primer en donar-nos el resultat.
Quan un d’aquests mètodes finalitza el seu càlcul, envia un signal al seu procés pare (un signal
del tipus SIG_USR1 el mètode1, i de tipus SIG_USR2 el mètode2), i escriu per la seva sortida estàndar (en el format intern de la màquina) el resultat. Si en qualsevol moment a un dels dos mètodes li arriba un signal del tipus SIGTERM, abortarà inmediatament el càlcul sense escriure res per
la seva sortida estàndar.
Volem aplicar aquest càlcul a 3 enters i obtenir el resultat de la forma més ràpida possible. Com
a priori no sabem quin dels mètodes ens donarà abans el resultat, executarem tots dos mètodes concurrentment, i quan amb un obtinguem el resultat aturarem l’altre.
Heu d’escriure un programa que tindrà com a únic paràmetre un nom de fitxer (on estaran els 3
nombres enters). Aquest programa escriurà per la seva sortida estandar el resultat del càlcul, indicant, a més a més, per quin mètode ha obtingut el resultat.
Si passats 10 segons cap dels mètodes ens dona un resultat, aturarem inmediatament tots dos
mètodes i el programa finalitzarà notificant-ho.
Problema 4.24. Timeout
Haced un programa llamado timeout que ejecute otro comando. Si dicho comando no acaba en el
tiempo especificado, será abortado cuando se acabe el plazo. El formato del comando será:
timeout [-sec] comando [lista_de_parámetros_del_comando]
Si no se especifica sec se considerará un segundo.
PROBLEMES D’EXAMEN
Problema 4.25. Minish
A) Es tracta de fer un petit intèrpret de comandes (o shell) en llenguatge C i utilitzant crides a
sistema UNIX. Volem que tingui les següents característiques:
• El seu nom és ‘minish’; ha d’escriure el prompt “minish% ”.
• Ha de poder executar qualsevol comanda externa com ho faria el shell tradicional.
Problemas Tema 4:Gestión de procesos en Unix
6
• Les comandes externes poden ser a qualsevol directori contingut a la variable d’entorn
PATH.
• ‘Minish’ ha d’esperar que acabi cada fill - execució en foreground - i ha d’escriure el
resultat que torna el fill a la pantalla.
• Quan acaba l’execució d’una comanda, ha de tornar a treure el prompt.
Considereu que existeixen les següents rutines:
1) void analitzar_línia (
char * línia_entrada, /* Entrada */
int * n_arguments,
/* Sortida */
char * arguments [MAX], /* Sortida */
char * stdin ,
/* Sortida */
char * stdout ,
/* Sortida */
char * stderr );
/* Sortida */
que rep línia_entrada (llegida per ‘minish’ amb un read ()), la divideix en
els seus components i retorna la quantitat d’arguments que ha trobat
(n_arguments), quins són (arguments) i els noms dels fitxers on l’usuari
vol redireccionar els canals d’entrada, sortida i error. Si algun dels components no és present a la línia de comandes, el valor retornat és NULL.
Exemple: amb la següent línia,
minish% ls -l >fitxer prova
la funció ens retornarà:
n_arguments = 3
arguments[0] = “ls”
stdin = NULL
arguments[1] = “-l”
stdout = “fitxer”
arguments[2] = “prova”
stderr = NULL
arguments[3] = NULL
...
arguments[MAX] = NULL
2) void obtenir_path (
int * npath,
/* Sortida */
char * array_path [MAX]); /* Sortida */
que llegeix els paths continguts a la variable PATH i retorna la quantitat
de directoris on hem de buscar i els seus noms complets des de l’arrel.
B) Què provocaria la següent comanda executada des del ‘minish’ ?
minish% rm *
C) Indiqueu esquemàticament tots els passos amb què farieu que si el ‘minish’ rep un signal
SIGUSR1, enviï un mail a l’usuari actual, amb el missatge:
minish aborted by SIGUSR1
els usuaris que treballaven a la màquina són:
...
iso2302
tty01 ...
iso1205
tty02 ...
... (la sortida típica de who)
Problema 4.26.
Tenim un sistema operatiu UNIX amb el csh com a intèrpret de comandes i rebem la següent
Problemas Tema 4:Gestión de procesos en Unix
7
comanda:
prompt% ls -R / | cat | sort > fitxer
( “ls -R /” lista recursivament tots els fitxers de tots els directoris)
1. Què haurà de fer el shell pel que fa a la creació de processos i la gestió de canals
d’entrada/sortida?
Especifiqueu les crides a UNIX i l’esquema del shell per aquest cas concret.
Quin és l’ordre en que acaben el processos i quin és el motiu que ho provoca?
2. El procés cat rep un SIGKILL a la meitat de la seva execució.
Què desencadena això a cadascun dels processos?
Què caldria afegir al codi font del programa ls per a que informi
l’usuari quan s’ha produït aquesta situació?
Consulteu les crides read i write pel que fa a les pipes.
Problema 4.27. El mensajero
Escribid un programa tal que dado un usuario localice en qué pantalla se encuentra conectado y le
envíe un mensaje. El mensaje se introducirá por la entrada estándar y aparecerá en la pantalla del
destinatario. Este programa debe controlar los errores que puedan producirse al invocar las llamadas al sistema susceptibles de fallar (fork, open...).
mensajero iso1227 <fich.mens
P.e:
Envía un mensaje a iso1227 que está contenido en el fichero “fich.mens”. Para localizar el terminal, el proceso deberá llamar al comando who seguido de grep para determinar si el usuario está
conectado y en qué pantalla se encuentra.
prompt% who
som03 pts/2 Jan 12 11:21
iso1227 pts/6 Jan 12 08:12
iso3109 pts/0 Jan 12 11:34
iso2223 pts/10 Jan 12 10:35
prompt% who | grep iso1227
iso1227 pts/6 Jan 12 08:12
En el caso de que el usuario no estuviera el resultado sería una línea vacía.
prompt% who | grep iso5555
prompt%
Realizad el programa en lenguaje C, con llamadas directas al sistema y funciones de librería que
no llamen al sistema. Podéis tener en cuenta que el nombre de terminal empieza en la columna 11.
Problema 4.28. Betes i fils
Escriviu el programa, en llenguatge C, greplc que donat un patró i un conjunt de fitxers, escriu
per la seva sortida estàndar per a cada fitxer que contingui el patró, únicament el seu nombre
total de línies i el seu nom.
greplc patró fitxer1[ fitxer2 ... fitxerN]
Heu de fer servir els executables de les comandes grep i wc, que tenen el següent comportament:
Problemas Tema 4:Gestión de procesos en Unix
8
• grep patró [fitxer] Busca les aparicions a fitxer de la cadena de caràcters patró, treient
per la sortida estàndar totes les línies que contenen patró.
Com a codi de finalització ens retornarà 0 si ha trobat alguna aparició del
patró, 1 si no n’ha trobat cap i 2 si s’ha produit algun error. Si el paràmetre fitxer no és present, grep llegirà de la seva entrada estàndar.
• wc -l [fitxer] Escriu per la seva sortida estàndar el nombre de línies que conté fitxer i el
nom del fitxer. Si el paràmetre fitxer no és present, wc llegirà de la seva entrada estàndar
i per la sortida estàndar únicament escriurà el nombre de línies de l’entrada estàndar.
Exemple:
montgros> grep main errors.c
montgros> grep main prova.c
main(argc, argv)
montgros> grep main xemeneies1.c
main(argc, argv)
montgros> grep main xemeneies2.c
main(argc, argv)
montgros> greplc main errors.c prova.c xemeneies1.c xemeneies2.c
50 prova.c
50 xemeneies1.c
57 xemeneies2.c
Problema 4.29. Fes-t'ho tu mateix
Volem escriure un programa que executi el mateix que faria la sentència de Bourne shell:
$ primer opcio | segon 2>sortida_error &
i es proposa el següent codi, que heu de completar amb les crides al sistema oportunes. Així,
aquest programa s'executarà amb la següent comanda (carr es el nom de l'executable):
$ carr primer opcio segon sortida_error
main(int argc,char *argv[])
{
char buff[256];
char *param[4];
if (analitza_arguments (argc,argv,param)==0)
{
sprintf (buff, ”Número incorrecte de parametres\n”);
write (2, buff, strlen(buff));
exit (1);
}
/* Segons l'exemple anterior, en aquest punt tindrem:
param[0] = “primer”;
Nom del primer programa executable
param[1] = “opcio”;
Argument per el primer executable
param[2] = “segon”;
Nom del segon programa executable
param[3] = “sortida_error”; Nom de fitxer on surten els missatges
d'error
*/
....
exit (0);
}
Nota: Per fer el dos últims apartats, marqueu a la solució del apartat 1 el punt d'inserció de nou
codi i detalleu a continuació quin és el codi afegit.
Problemas Tema 4:Gestión de procesos en Unix
9
1. Completeu (en el punt marcat amb punts suspensius) el codi anterior amb les crides
al sistema Unix necessàries. Especifiqueu completament els paràmetres de les crides
al sistema.
2. Afegiu el codi necessari de forma que, mentre s'executa la comanda anterior, al
premer les tecles (control-C) no s'acabin els processos creats. Nota: En premer el
control-C, els processos creats reben el signal SIGINT.
3. Afegiu més codi de forma que si els processos fill no acaben en 5 segons, s'escrigui
un missatge per la sortida d'error i acabin tots els processos.
Problema 4.30.
Queremos que un proceso muestre un mensaje por pantalla cada 5 segundos. Para ello tenemos:
void funcionAlarma() {
if(write(1,”recibida alarma”,15)==-1)
mostrar_error(“en el write”);
alarm(5);
}
void main(){
signal(SIGALRM,funcionAlarma);
alarm(5);
while(1) {
pause();
}
}
Sin embargo, sólo aparece un mensaje de “recibida alarma”, y el proceso muere al recibir el
segundo signal ¿Por qué ocurre esto? ¿Qué harías para solucionarlo?
Problema 4.31. El impaciente
Queremos escribir una utilidad (“wcTemporizado”) que nos indique, dada una lista de ficheros
(como máximo, 10), el que tiene el máximo número de líneas, y el total de éstas. Existe un
problema añadido, y es que queremos calcular este valor antes de N segundos (N es el primer
parámetro que se le pasa al programa). Si en N segundos no se ha podido calcular qué fichero es el
que tiene más líneas, el programa terminará indicando que se ha quedado sin tiempo. Por
ejemplo:
montgros_$ wcTemporizado 5 uno.txt dos.txt .login
fichero: uno.txt lineas: 34
montgros_$ wcTemporizado 1 uno.txt dos.txt gigante.txt
wcTemporizado: alarma antes de completar el trabajo
Para ello escribiremos un programa que hará uso del comando wc, utilizando éste para contar las
líneas de cada uno de los ficheros que se le pasan como línea de comandos. Sabemos que invocar
a wc de la siguiente forma:
wc -l nombre_fichero
sirve para contar las líneas que tiene un fichero, y escribe por la salida estándar el total de líneas y
el nombre del fichero. Además disponeis de la función:
Problemas Tema 4:Gestión de procesos en Unix
10
int filtrarSalida(char *);
que, dada una cadena de caracteres (la salida del comando wc), elimina de ella el nombre del
fichero y retorna un número entero con el total de líneas. Se os pide que escribais el programa
wcTemporizado.c utilizando sólo las llamadas a sistema UNIX vistas en clase.
Problema 4.32. Watchfor
Queremos implementar un programa en C que dado un username nos avise de cuándo ese usuario
entra en el sistema. El funcionamiento deseado es que cada cierto tiempo T (por defecto 180 segundos) el proceso compruebe si el usuario ha entrado en la máquina. Si ha sido así mostrará un mensaje por pantalla y acabará. Si por el contrario, el usuario no ha entrado, el proceso se quedará
bloqueado durante T segundos, y pasado ese tiempo volverá a realizar la comprobación. Este programa aceptará como parámetros el username y, opcionalmente, el número de segundos que tiene
que esperar entre comprobaciones.
Para facilitar la implementación de la comprobación, utilizaremos los comandos del shell who
y grep, que se ejecutarán en dos procesos separados, comunicados por una pipe ordinaria.
Recordad que el comando who sin parámetros, muestra, por la salida estándar del proceso que
lo ejecuta, la lista de usuarios que en ese momento están conectados en la máquina. Este comando
devuelve 0 como código de finalización (parámetro de la llamada a sistema exit) si no ha habido
ningún error. Por su parte, el comando grep busca el patrón que se le pasa como parámetro en lo
que recibe por la entrada estándar del proceso que lo ejecuta. El código de finalización de este comando será 0 si ha encontrado el patrón, y 1 si no lo ha encontrado.
Se os pide el código de este programa, en el que deberéis utilizar las llamadas a sistema de Unix
vistas en clase.
Problema 4.33.
Compara los dos códigos siguientes. Indica claramente el resultado de la ejecución de cada uno de
ellos explicando el por qué de las diferencias de funcionamiento.
Problemas Tema 4:Gestión de procesos en Unix
11
void func(){
signal(SIGALRM, func);
}
main(){
pid_t pid;
status_t status;
signal(SIGALRM, func);
pid = fork();
switch (pid) {
case -1:error(“fork”); exit(1);
case 0: while(1){
alarm(5);
pause();
write(1,”alarma\n”,7);
}
break;
default:pid=wait(&status);
write(2,”fin ejecución\n”,14);
}
}
Código A
/* fichero padre */
void func(){
signal(SIGALRM, func);
}
main(){
pid_t pid;
status_t status;
signal(SIGALRM, func);
pid = fork();
switch (pid){
case -1: error(“fork”); exit(1);
case 0: execlp(“hijo”, “hijo”,(char *)0);
default: pid=wait(&status);
write(2,”fin ejecución\n”,14);
}
}
--------------------------------------/* fichero hijo */
main (){
while (1){
alarm(5);
pause ();
write(1, “alarma\n”,7);
}
}
Código B
Problema 4.34.
Se quiere implementar un nuevo comando que permita lanzar un proceso con el tiempo de ejecución limitado. Este comando, que se llamará lanzar, recibirá como parámetros el tiempo máximo
de ejecución (medido en segundos), el nombre del ejecutable que se quiere lanzar y sus parámetros
(si es que necesita alguno). El comando lanzar se queda a la espera de que el proceso que ha creado
acabe. Si pasado el tiempo máximo el proceso no ha acabado, lanzar mostrará por el canal de errores estándar un mensaje de aviso, y enviará al proceso el signal SIGKILL.
En la siguiente figura se ven dos ejemplos de uso de este comando. En el primero, se lanza el
ejecutable ls, con su opción -l, y se le concede 1 segundo de ejecución. Como el comando ls no
finaliza en ese espacio de tiempo, el comando lazar lo mata y da por el canal de errores el mensaje
de aviso. En el segundo caso se vuelve a lanzar el comando ls con la opción -l, pero esta vez con
5 segundos de tiempo. En este caso el ejecutable ls acaba a tiempo.
Problemas Tema 4:Gestión de procesos en Unix
12
montgros% lanzar 1 ls -l
(después de 1 segundos)
error: el proceso ls se ha pasado de
montgros% lanzar 5 ls -l
drwx------ 2 user1 grupo1 1024 Oct 5
drwx------ 2 user1 grupo1 1024 Nov 8
-rw------- 2 user1 grupo1 1024 Dec 6
montgros%
tiempo
directorio1
directorio2
fichero1
• Escribid en C el código del comando lanzar, usando las llamadas a sistema de Unix que
necesitéis.
• Suponed ahora que queréis redireccionar la salida estándar del ejecutable que lanzamos
mediante el comando lanzar. Sin modificar el código que habéis escrito ni el del
ejecutable, ¿es posible hacer esta redirección? ¿Cómo ejecutaríais el comando lanzar?
Justifica brevemente tus respuestas.
Problema 4.35.
Suponed que interesa realizar un cálculo matemático en el menor tiempo posible. Se conocen dos
métodos para hacer este cálculo, y se dispone de un ejecutable para cada uno de estos métodos.
Estos ejecutables (de nombre calculo1 y calculo2) reciben como parámetros los dos argumentos
que necesitan para realizar el cálculo y muestran por salida estándar el resultado del mismo. En la
siguiente figura podéis ver el código de uno de estos ejecutables (el otro es igual, cambiando la llamada a la función metodo1, por la llamada a metodo2).
/* calculo 1 */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int metodo1(); /*prototipo de la funcion*/
main (argc, argv)
int argc;
char *argv[];
{
int arg1, arg2, res;
char buf[80];
arg1=atoi(argv[1]);
arg2=atoi(argv[2]);
res=metodo1(arg1,arg2);
sprintf(buf,”%d”,res);
res=write (1,buf,strlen(buf);
if (res<0){
sprintf(buf,”%s”,strerror(errno));
write(2,buf, strlen(buf));
exit(1);
}
}
Para averiguar cuál de los dos cálculos acaba antes, se ha pensado en implementar un programa
(evaluador) que cree 2 procesos, y que cada uno de estos procesos lance uno de los ejecutables.
Problemas Tema 4:Gestión de procesos en Unix
13
Este programa evaluador usará una pipe ordinaria para recibir el resultado del cálculo, y avisará
cada 30 segundos al usuario mientras no obtenga este resultado (este aviso será un mensaje por salida estándar). Una vez haya finalizado el proceso más rápido, el proceso evaluador deberá matar
a los procesos hijos que todavía no hayan acabado la ejecución y finalizar, mostrando por salida
estándar el resultado del cálculo, el tiempo que se ha tardado en obtenerlo y cuál de los métodos
ha sido el más rápido.
Se os pide el código del programa evaluador, suponiendo que disponéis de los ejecutables
calculo1 y calculo2.
Problema 4.36.
Di cuál crees que será el resultado de ejecutar cada uno de los siguientes códigos:
a)
b)
#include <signal.h>
#include <unistd.h>
#include <unistd.h>
void mi_rutina(){
signal(SIGALRM,mi_rutina);
write(1,”ALARMA!”,7);
}
main(){
int ret;
signal(SIGALRM,mi_rutina);
alarm(5);
ret=fork()
if (ret<0) {error();exit(1);}
pause();
if (ret==0)
write(1,”Soy el hijo\n”,12);
else
write(1,”Soy el padre\n”,13);
}
main(){
int ret;
int fd[2];
char buff[20];
pipe(fd);
ret=fork():
switch (ret){
case -1: error();exit(1);break;
case 0: close(0);dup(fd[0]);
execlp(“hijo”,”hijo”,(char *)0);
default: strcpy(buff,”Buenos dias!”);
close(fd[0]);
ret=write(fd[1],buff,strlen(buff));
if (ret<0){ error();exit(1);}
close(fd[1]);
}
}
/* fichero hijo */
main(){
int ret;
char buff[80];
ret=read(0,buff,sizeof(buff));
while (ret>0){
buff[ret]=’\0’;
ret=write(1,buff,strlen(buff));
if (ret<0){ error();exit(1);}
ret=read(0,buff,sizeof(buff));
}
if (ret<0){ error();exit(1);}
}
Problema 4.37.
Se quiere implementar una aplicación que realice N cálculos. Esta aplicación dejará el resultado de todos esos cálculos, junto con el tiempo que ha empleado para cada uno de ellos, en un
Problemas Tema 4:Gestión de procesos en Unix
14
único fichero. Se quiere además que los resultados aparezcan ordenados (por ejemplo: el resultado
del cálculo 2 debe aparecer después del resultado del cálculo 1 aunque haya acabado antes).
La aplicación tiene que estar formada por dos programas diferentes.
Uno de ellos será ejecutado por un único proceso (organizador), y es el encargado de crear
todos los procesos que ejecutarán realmente los cálculos. Creará un proceso para cada uno de los
cálculos pasándole como parámetro el identificador del cálculo que debe realizar (este identificador será simplemente un entero de 0 a N-1). Además el organizador es el encargado de que los
resultados aparezcan ordenados en el fichero. Para ello, avisará mediante un signal de tipo
SIGUSR1 al proceso que tiene el turno para escribir en el fichero de resultados.
El otro programa es el que ejecutará cada uno de los procesos calculadores. Este código recibe como parámetro el cálculo que debe realizar y ejecuta la función cálculo, que podéis suponer
ya implementada, y que tiene el siguiente interfaz:
int cálculo(int id_calculo);
Esta función devuelve el resultado del cálculo que identifica el parámetro id_calculo.
Además deberá contabilizar el tiempo que ha invertido en hacer el cálculo. Cuando tenga el
resultado deberá comprobar si ya es su turno para escribir el resultado, y si no es así esperar hasta
que le toque. Cuando sea su turno mostrará por salida estándar una línea con el siguiente formato:
id_calculo:resultado:tiempo de ejecución
Se pide la implementación del código de los dos programas.
Problema 4.38.
Escribid los siguientes programas en C, usando las llamadas a sistema de Unix vistas en clase:
ping_pong: este programa recibe como parámetro un valor inicial, que le pasará al proceso
ping como parámetro (para que éste inicialize el cálculo). Creará dos pipes ordinarias para que sus
procesos hijos se comuniquen entre sí, y a continuación creará dos procesos: uno ejecutará el programa ping y otro ejecutará el proceso pong. Una vez creados los dos procesos hijos, deberá esperar 30 segundos y a continuación enviar un signal de tipo SIGINT al proceso ping, para que éste
acabe la ejecución, y esperar a que los dos hijos acaben. Por último, deberá mostrar por salida estándar el resultado del cálculo, que será el código de finalización del proceso ping.
ping: este programa recibe como parámetro el valor para inicializar el cálculo. A continuación, ejecuta un bucle que acabará cuando reciba el signal de tipo SIGINT. En este bucle, multiplica por 2 ese cálculo, lo muestra por salida estándar, y se queda a la espera de recibir por entrada
estándar el cálculo modificado. Cuando reciba el signal de tipo SIGINT acabará inmediatamente,
devoviendo como código de retorno el cálculo tal y como estaba en ese momento.
pong: este programa no recibe ningún parámetro. Ejecuta un bucle que consiste en recibir
por entrada estándar un valor, y escribir por salida estándar ese valor multiplicado por 3. El bucle
acabará cuando la lectura de entrada estándar indique final de fichero.
Problema 4.39.
Escribid dos programas en C, usando las llamadas a sistema de Unix, que se comporten de la
siguiente manera.
• El primer programa (escritor_padre) recibirá como parámetro el nombre de un fichero
Problemas Tema 4:Gestión de procesos en Unix
15
(nom_fich) y un entero (tiempo) que representará el tiempo que debe durar la escritura. Este
programa deberá crear otro proceso que ejecutará el segundo programa (escritor_hijo). A partir de este momento, mientras no se acabe el tiempo recibido como parámetro, deberá repetir la
siguiente secuencia:
1. Escribir en nom_fich una línea con su pid
2. Avisar a su hijo de que le toca escribir
3. Y esperar a que le vuelva a tocar el turno de escritura.
Cuando se acabe el tiempo, avisará a su hijo de que tiene que acabar la ejecución, y mostrará
por salida estándard un mensaje con el número de líneas que se han escrito en el fichero.
• El otro programa (escritor_hijo) mientras no reciba el aviso de fin de ejecución repetirá la
siguiente secuencia de ejecución
1. Esperar a que le toque el turno
2. Escribir en nom_fich una línea con su pid
3. Avisar al padre de que le toca escribir
Cuando el padre le avise de que se acaba la ejecución este proceso acabará indicando como
código de retorno (valor del exit) el número de líneas que ha escrito en el fichero.
Problema 4.40.
Dado el código del programa prog:
/* PROGRAMA prog */
#include <unistd.h>
#include <signal.h>
main(int argc, char *argv[]){
int pid1, pid2, ppid, mipid, valor;
int fd[2];
char msg[80];
pid1 = fork();
pipe(fd);
pid2 = fork();
A
if (pid2 == 0) {
close (fd[1]);
ret = read(fd[0], &ppid, sizeof(int));
kill (ppid, SIGKILL);
close (fd[1]);
}
else {
close (fd[0]);
mipid=getpid();
write(fd[1], &mipid, sizeof(int));
close (fd[1]);
wait(&valor);
}
strcpy(msg, ”Objetivo cumplido!”);
write(1,msg,strlen(msg));
}
1. ¿Cuántos procesos tendremos en ejecución en el punto A?
Problemas Tema 4:Gestión de procesos en Unix
16
2. ¿Cuántas pipes crea este programa? Representa el estado de la tabla de ficheros
abiertos y de la tabla de canales de cada proceso, suponiendo que el programa se
lanza sin redireccionar la entrada-salida y que todos los procesos se encuentran en el
punto A.
3. ¿Cuántas veces aparecerá por salida estándard el mensaje “Objetivo cumplido!”?
4. Describe brevemente lo que hace este código.
Problema 4.41.
Dado el siguiente código, se pretende que al final de su ejecución la primera línea de un fichero
llamado pids contenga el pid del proceso hijo, y la segunda línea contenga el pid del proceso padre.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
/* miprog */
#include <unistd.h>
#include <fcntl.h>
main(){
int ret;
int fd_pids;
char buffer[50];
ret = fork();
if (ret == 0){
sprintf(buffer,”%d\n”,
write(fd_pids, buffer,
} else {
sprintf(buffer,”%d\n”,
write(fd_pids, buffer,
}
}
getpid());
strlen(buffer));
getpid());
strlen(buffer));
Suponiendo que el programa se lanza sin redireccionar ningún canal estándar, contestad a las
siguientes preguntas, justificando vuestras respuestas:
1. En qué punto o puntos del código añadiríais la llamada a sistema open y con qué
parámetros
2. ¿Creéis que es necesario añadir alguna llamada a sistema más para asegurar que el
funcionamiento sea el esperado? Si es así, indica cuál (o cuales), en qué punto(s) y
con qué parámetros.
Si por el contrario, lanzáramos el programa de la siguiente manera:
angren% miprog > pids
3. ¿Deberíais modificar de alguna manera vuestra propuesta para que su
funcionamiento fuera el mismo? ¿Por qué?
Problemas Tema 4:Gestión de procesos en Unix
17
Problema 4.42.
Se quiere implementar un programa en C que use las llamadas a sistema de Unix. El comportamiento de este programa debe ser el siguiente: recibirá como parámetro el nombre de un fichero
fuente y el nombre de un fichero destino, e intentará copiar en menos de 30 segundos el contenido
del fichero fuente en el fichero destino.
Para hacer la copia del fichero se quiere implementar la estructura que aparece en la siguiente
figura. El programa inicial creará dos procesos hijos. Cada hijo ejecutará el programa prog_hijo
que también aparece en la figura. La comunicación entre los procesos se hará mediante pipes ordinarias (pipe1 y pipe2). El proceso padre enviará al primer hijo a través de pipe1 el contenido del
fichero fuente. El primer hijo reenviará el contenido que reciba al segundo hijo a través de pipe2.
Y será el segundo hijo el encargado de escribir en el fichero destino el contenido del fichero fuente.
El proceso padre es el encargado de controlar el tiempo. Si al cabo de los 30 segundos no se
ha acabado de hacer la copia deberá matar a sus dos hijos, sacar un mensaje de error por el canal
de salida de errores estándar y eliminar el fichero destino.
fuente
/* prog_hijo */
#include <unistd.h>
proceso padre
pipe 1
destino
proceso hijo 1
pipe 2
main(){
int ret;
char buffer[80];
ret = read(0, buffer, 80);
while (ret > 0){
write(1, buffer, ret);
ret = read(0, buffer, 80);
}
}
proceso hijo 2
Problemas Tema 4:Gestión de procesos en Unix
18
Descargar