Programa: Conjunt comprès per codi i dades que es troba al disc que resolen
una necessitat concreta dels usuaris.
Procés: Quan un programa s'executa, es crea un procés, que controla
la seua execució, els recursos que consumeix i el seu estat. Inclou:
Comptador del programa: Indica el punt o la instrucció que esta executant.
Imatge de memòria: Conté tot el espai en memòria utilitzat i les dades
emmagatzemades.
Estat del processador: Valor dels registres del processador que s'utilitzen.
Usuari: Usuari que ha iniciat el procés, que marcarà els permisos dels
quals disposa el procés (recursos del sistema que pot accedir...)
Quan s'interromp l'execució d'un procés per alguna causa, es veuran més endavant,
es desa una còpia dels tres elements esmentats a dalt per poder restaurar
l'execució del procés al mateix punt en què es va interrompre.
Els processos són entitats independents del programa que s'executa.
Dos processos que executen el mateix programa poden coexistir.
Per exemple, es poden tenir oberts dos fitxers PDF alhora amb el mateixa
aplicació. Un altre exemple és el navegador Chrome. Chrome
crea un procés diferent per cada pestanya que es té oberta.
Executable: És un fitxer que conté el programa en binari (llenguatge
màquina) i que es pot executar en el dispositiu.
Sistema operatiu: Peça de programari encarregada de gestionar de
manera eficient tots els recursos de maquinari i programari del dispositiu,
proporcionat un entorn amigable i fàcil d'utilitzar per l'usuari,
i una interfície comuna per tot el programari instal·lat en aquest.
Dimoni (daemon) o servei: És un procés que s'executa en segon pla i
no és accessible per l'usuari. La seua funció és proporcional alguna funcionalitat o servei
al sistema i a la resta de processos.
Exemples de dimonis a Linux
systemd: Dimoni d'administració de sistema dissenyat exclusivament
per l'API del nucli Linux.
networking: Gestionar les interfícies de xarxa del dispositiu.
crond: El dimoni del planificador per a accions basades en el temps,
com ara actualitzacions de programari o comprovacions del sistema.
La computació concurrent permet que multiples programes s'estiguen executant
alhora. Per exemple, es pot estar escoltant música, mentre s'utilitza un
sistema de compartició de fitxers p2p i es redacta un document de text.
Per poder implementar la computació concurrent, cal tindre en compte
diferents escenaris:
Dispositius amb un únic processador amb un únic nucli i sense fils:
En aquest cas, només es pot executar un procés a la vegada. Per donar
la sensació que diversos processos s'executen a la vegada, el sistema
operatiu va canviant de procés en execució en poc de temps (mil·lisegons).
Diversos nuclis en un mateix processador: Hui en dia és molt normal
que els processadors continguen diversos nuclis (també en mòbils).
Cada nucli pot executar un programa diferent. Com tots els processos
comparteixen memòria, la comunicació entre ells és molt ràpida i senzilla
d'implementar.
També es pot donar el cas que cada nucli execute una instrucció diferent
del mateix programa. Aquesta tècnica rep el nom de programació paral·lela,
que permet millorar considerablement el rendiment programa. Per exemple,
quan s'edita un document de text, un nucli s'encarrega de gestionar
l'edició del text i un altre de revisar la correcció gramatical del text.
Sistemes distribuïts: Sistema que consisteix en diferents equips
distribuïts en xarxa. Cada equip disposa del seu propi processador i memòria
i la gestió conjunta de tots els equips s'anomena programació distribuïda.
Millora el rendiment considerablement, però la la gestió i comunicació entre
processos és més complicada, ja que no comparteixen memòria i requereixen
d'esquemes de comunicació específics i costosos a través de la xarxa.
El cloud computing estaria dins d'aquesta categoria.
El sistema operatiu (SO), com qualsevol altre programa, necessita estar
en memòria per poder ser executat. Hi ha una part del sistema operatiu que
s'encarrega de gestionar tota la resta i que ha d'estar sempre em memòria:
el nucli o kernel.
El kernel gestiona els recursos de l'ordinador, permetent l'accés a aquests
mitjançant les trucades al sistema.
El kernel és una part molt xicoteta del SO, sobretot si es compara,
amb tot el necessari per implementar la interfície gràfica.
A la resta de SO se'n diu programes del sistema.
El nucli del sistema generalment treballa sobre la base
d'interrupcions (IRQ – Interrupt ReQuest).
Una interrupció és la suspensió temporal d'un procés per executar
la rutina que gestiona aquesta interrupció. Mentre s'atén una interrupció,
es deshabilita l'arribada d'altres interrupcions. Les interrupcions solen
estar generades per trucades al sistema.
Les trucades al sistema es programen amb llenguatges de baix nivell,
com C o C++, pel fet que permeten l'accés a nivells més baixos del maquinari.
En els llenguatges d'alt nivell, els desenvolupadors fan ús d'APIs del
sistema. Les més comunes són Win32 (Windows), API POSIX (per a sistemes
Unix en què s'inclou GNU Linux i Mac OS).
Com hem dit anteriorment, un procés és l'estat d'un programa en un moment donat
de la seva execució amb tot el que això significa: comptador, memòria i
registres de la CPU.
És el SO l'encarregat de posar en execució i gestionar els processos.
En els sistemes que suporten programació concurrent, els processos poden
passen per diferents estats al llarg del seu cicle de vida.
Els canvis d'estat també són gestionats pel sistema operatiu.
Hi ha diversos models per implementar el cicle de vida d'un procés.
A punt o esperant: Programa preparat per entrar a la CPU. Ja se li
ha assignat zona en memòria.
Execució: La CPU està executant el procès.
Bloquejat: Sense possibilitat d'entrar a la CPU, per exemple,
per què està esperant una operació d'E/S.
Model de cinc estats: Afegeix dos estats al model anterior (blanc a la imatge).
Creat: S'està creant o s'acaba de crear, però encara no esta llest
per ser executat. Per exemple, si s'ha arribat al límit de la memòria.
Acabat: El procès ha finalitzat i allibera els recursos i la memòria
utilitzada. També passa a aquest estat si ocorre un error i deixa
d'executar-se.
Model de set estats: Afegeix dos estats més (tota la imatge).
Hi ha moments en què es poden trobar molts processos bloquejats, ocupant
memòria i no deixen que altres processos puguen entrar en execució. En
aquests casos, és important que es permitisca realitzar un intercanvi (swap)
i que aquests processos bloquejats passen a emmagatzemar-se en disc,
alliberant memòria principal.
A punt i suspés: Processos preparats per entrar en execució però
que es troben en memòria secundària.
Bloquejat i suspés: Processos bloquejats però que es troben en
memòria secundària.
Una de les funcions del SO és la gestió de processos,
i en concret, gestionar els diferents estats dels processos
i determinar quins processos passen a executar-se.
Per realitzar aquesta tasca, fa ús de diferents cues.
Cua general de processos: conté tots els processos del sistema.
Cua de processos preparats: conté aquells processos llestos per executar-se.
Cues de dispositiu: conté els processos que esperen alguna operació E/S.
El SO necessita un planificador de processos que s'encarrega de
gestionar les cues de processos. Hi ha dos tipus de planificació:
Curt termini: S'encarrega de triar quin és el següent procés en entrar
a la CPU, aquesta operació s'executa moltes vegades i cada poc temps
(mil·lisegons), per la qual cosa l'algorisme ha de ser senzill.
Hi ha tres tipus d'algorismes per a aquesta planificació.
Sense desallotjament: Un procés que entra passa a execució no
desallotja la CPU fins que no acaba o es bloqueja.
Exemples: FIFO (First-In First-Out) i SJF (Shortest Job First).
Amb desallotjament: Permeten desallotjar el procès del processador
encara que aquest no haja acabat. Examples: Round Robin o SRT (Shortest
Remaining Time) sense prioritat, o planificacions que permeten
que els processos tinguen diferents nivells de prioritat, com el
Multilevel feedback queue.
Llarg termini: S'encarrega de gestionar els processos que passen
a la cua de preparats, que s'invoca amb poca freqüència.
Cada procés és únic i impredictible. Els algorismes de planificació necessiten
saber de quin tipus és per planificar els processos de la millor manera possible.
Podem trobar processos:
Orientats a CPU (CPU-bound): Normalment sols utilitza el processador
per la seua execució.
Orientats a E/S (IO-bound): L'execució depén del sistema E/S i els seus
recursos, com els discs durs o perifèrics.
Tots els processos han segut iniciats d'alguna manera. Alguns, s'han
llançat per el SO, alguns altres els ha executat l'usuari, però
cap d'ells ha aparegut espontàniament. Això significa que qualsevol procés,
ha segut iniciat per un altre procés.
Quan el SO arranca, inicia un procés amb la interfície gràfica
i el gestor de finestres.
Quan l'usuari clica sobre l'accés directe del navegador, el gestor gràfic
inicia el navegador en una nova finestra.
Quan l'usuari obri una nova pestanya, el navegador crea un procés per gestionar
aquesta pestanya.
Qualsevol procés en execució depén del procès que l'ha creat i estableix
un enllaç entre ells. El procés creador s'anomena pare i el creat fill.
Quan s'inicia l'ordinador, el gestor d'arrancada s'encarrega d'executar el
kernel del SO i es crea el procés principal, sobre el qual aniran creant-se
la resta de processos de manera jeràrquica. En Linux, aquest procés s'anomena
init. Podem utilitzar la comanda pstree per veure l'arbre de processos.
Tots els processos s'identifiquen mitjançant el PID (Process Identifier),
que és únic per a cada procés.
Les operacions amb processos es realitzen mitjançant trucades al sistema,
ja que l'encarregat de gestionar-los és el sistema operatiu, per tant,
aquestes operacions poden ser realitzades de diferent maneres depenent
del sistema operatiu en el qual es trobeu.
Les operacions que es poden invocar des d'un programa son:
Crear process: Crea un nou procés. Aquesta operació pot ser:
Iniciar un programa diferent: Cal indicar el programa que es desitja
executar i els arguments.
Fork: Realitza un duplicat del procés que crea el procés, que contínua
l'execució des del mateix punt, però continuen per separat.
Els processos poden fer ús de recursos compartits. La memòria compartida
és una regió de la memòria a la qual poden accedir diferents processos que
col·laboren. El SO s'encarrega de crear i establir els permisos
dels processos que poden accedir a aquest espai de memòria.
Esperar (i bloquejar): En alguns casos, els processos necessiten
coordinar-se i esperar a que un altre procés acabe la tasca que està
realitzant per poder continuar la seua execució. Això es fa mitjançant
la operació wait.
Acabar process: Un procès pot acabar de diferents maneres. Per ell mateix,
el procés acaba si arriba a la última instrucció o si es crida a la funció
exit(return_code). Aquesta funció rep el paràmetre return_code, que
és un codi intern per identificar el motiu pel qual ha acabat.
Si acaba perquè arriba a la última instrucció, es crida a aquesta funció
de manera automàtica amb un valor de 0. Qualsevol altre valor distint
a 0, indica que ha acabat amb algun error i el programa ha fallat.
El desenvolupador és el responsable de especificar els codis d'error
del seu programa.
El procés pare té "control" sobre el procés fill, per tant,
també pot acabar amb la seua execució. Per fer-ho, existeix
l'operació destroy, que acaba abruptament l'execució del fill.
Es podria donar el cas que el procés pare acabe abans que el procés fill.
Si això ocorre, es diu que el procés fill és un procés orfe.
Aquesta situació es gestionada de diferent manera per cada sistema operatiu.
Alguns SO no permeten aquesta situació, i realitzen una terminació en cascada,
que termina tots els processos fills si el procés pare acaba.
En Java, existeix la classe Process
que representa un procés del sistema.
Existeixen dos mètodes que serveixen per crear processos i retornen
un objecte de la classe Process, que serveix per gestionar aquest nou
procés.
Els dos mètodes anteriors poden llançar una excepció d'E/S:
IOException.
Això pot ocórrer per diferent motius, com que no es trobe la comanda o
que l'usuari no tinga permisos per executar eixe programa, entre altres motius.
Per tant, cal crear el procés dins d'un bloc try{ ... } catch { ... }.
El procés pare pot esperar que acabe el procés fill.
En Java, aquesta es realitza mitjançant la classe Process amb el mètode:
public int Process.waitFor():
El procés actual espera a que el procés representat per Process acabe.
Retorna el codi de eixida del procés. El valor 0 indica una
acabada normal.
args={"myCommand","myArg1","myArg2"};ProcessBuilderpb=newProcessBuilder(args);Processp=pb.start();intreturnCode=p.waitFor();System.out.println("L'execució de "+Arrays.toString(args)+" retorna "+returnCode);
En els dos casos, és pot utilitzar els mètodes isAlive() o waitFor()
per comprovar si ha acabat o esperar que acabe respectivament.
args={"myCommand","myArg1","myArg2"};ProcessBuilderpb=newProcessBuilder(args);Processp=pb.start();p.destroy();System.out.println("El procés: "+Arrays.toString(args)+p.isAlive()?" està viu.":" ha acabat.");
Aquest programa crea un nou programa a partir dels arguments passats al programa RunProcess.
El procés és creat mitjançant la classe ProcessBuilder.
Una vegada creat, el procés pare espera a que acabe el procés fill i imprimeix per pantalla
el codi de retorn del procés fill.
RunProcess.java
packageud1.examples;importjava.io.IOException;importjava.util.Arrays;publicclassRunProcess{publicstaticvoidmain(String[]args){// Indica la comanda que utilitza aquest programa per iniciar un nou procésString[]program={"notepad"};ProcessBuilderpb=newProcessBuilder(program);try{// Inicia el procés fillProcessprocess=pb.start();System.out.printf("S'ha iniciat el procés: %s\n",Arrays.toString(program));// El procés Java (pare) Espera a que el procés fill finalitzeintcodiRetorn=process.waitFor();System.out.println("L'execució de "+Arrays.toString(program)+" retorna "+codiRetorn);}catch(IOExceptionex){System.err.println("Excepció d'E/S.");System.out.println(ex.getMessage());System.exit(-1);}catch(InterruptedExceptionex){System.err.println("El procés fill ha finalitzat de manera incorrecta.");System.exit(-1);}}}
Exemple d'execució:
String[] program = {"notepad"};: El programa RunProcess executa la comanda notepad, que crea un process amb l'editor de notes del sistema.
Després, espera a que acaba i retorna el codi 0: èxit.
String[] program = {"powershell", "sleep", "5"};: El programa RunProcess executa la comanda sleep 5 en la línia de comandes Powershell.
Aquest procés esperarà 5 segons i acabarà amb el codi 0: èxit.
String[] program = {"powershell", "noexisteix"};: El programa RunProcess intenta executar la comanda noexisteix en la línia de comandes Powershell,
que evidentment no existeix. Això fa que el procés acabe en el codi d'error 1: error.
Aquest programa crea un nou programa a partir dels arguments passats al programa DestroyProcess.
El procés és creat mitjançant la classe Runtime.
Una vegada creat, el procés pare termina el procés fill abans de que acabe i comprova si ha acabat.
Per últim, espera a que acabe i torna a mostrar si ha acabat.
DestroyProcess.java
packageud1.examples;importjava.io.IOException;importjava.util.Arrays;publicclassDestroyProcess{publicstaticvoidmain(String[]args){// Indica la comanda que utilitza aquest programa per iniciar un nou procésString[]program={"powershell","sleep","5"};try{Runtimeruntime=Runtime.getRuntime();Processprocess=runtime.exec(program);System.out.println("El procés: "+Arrays.toString(program)+(process.isAlive()?" està viu.":" ha acabat."));System.out.println("Destruint...");process.destroy();process.waitFor();System.out.println("El procés: "+Arrays.toString(program)+(process.isAlive()?" està viu.":" ha acabat."));}catch(IOExceptionex){System.err.println("Excepció d'E/S");System.err.println(ex.getMessage());System.exit(-1);}catch(InterruptedExceptionex){System.err.println("El procés fill ha finalitzat de manera incorrecta.");System.exit(-1);}}}
Exemple d'execució:
String[] program = {"powershell", "sleep", "5"};: El programa DestroyProcess executa la comanda sleep 5 en la línia de comandes Powershell,
que hauria d'esperar 5 segons. Acte seguit, comprova si està viu amb isAlive(), el destrueix i espera a que el fill acabe.
Com es pot observar, el procés fill acaba abans d'hora perquè s'ha terminat.