Multiprogramación
Procesos
Cecilia Hernández
2007-1
Terminología

Multiprogramación
Ejecutar multiples programas al
mismo tiempo
 Requiere multiplexar la CPU

• Tranferencia de control entre programas
en ejecución mediante
• Cambio de contexto

Proceso : Programa en ejecución
gcc
tiempo
firefox
word
firefox
Procesos



Abstracción de SO
de programa en
ejecución
Asociado a un
espacio de
direccionamiento
Adelanto, múltiples
hebras de control
comparten mismo
espacio de
direccionamiento
Espacio de direccionamiento
SP
stack
(mem dinámica)
heap
(mem dinámica)
PC
Datos estáticos
(data segment)
código
(text segment)
Multiplexando CPU en el tiempo

SO mantiene estructuras de datos para
identificar procesos

PCB (Process Control Block)
• SO matiene un PCB por cada proceso que está
ejecutando en el sistema (para cuando no están
usando CPU)

SO ejecuta cambio de contexto para quitar
y dar CPU a par de procesos


Salva estado de proceso que sale de CPU
en PCB de proceso
Recupera estado de PCB de proceso que
entra a CPU para luego ejecutarlo
PCB


Estructura de datos con muchos campos
 Identificador de proceso (PID)
 Estado de ejecución (Listo, en ejecución, bloqueado)
 PC, SP, registros
 Información de administración de memoria
 Usuario al que pertenece
 Prioridad en ejecución
 Información para administración
En linux
 Definida en task_struct (include/linux/sched.h)
• Posee muchos más campos de los mencionados arriba
Estados de los procesos
En ejecución
Interrupción
Se despacha a
CPU
Sale de CPU
listo
interrupción
(completa E/S)
Bloqueado
Espera E/S
Colas de procesos

SO mantiene diversas colas para
representar los procesos en el sistema



Cola de procesos listos: Procesos que están
en condiciones de ejecutarse esperando por
entrega de CPU
Cola de procesos bloqueados: Procesos que
esperan por alguna condición para estar
listos para ejecutarse
Cuando un proceso cambia de estado, su
PCB se desenlaza de una cola para
enlazarse a otra
Colas de Procesos
Ptr head
Ptr tail
firefox pcb
emacs pcb
cat pcb
firefox pcb
gcc pcb
Encabezado cola listos
Encabezado cola espera
Ptr head
Ptr tail

Hay muchas colas de espera, una por cada
tipo de espera (dispositivo E/S específico,
red, etc)
Cambio de contexto






Proceso mediante el cual se cambia de un proceso en
ejecución a otro
Proceso A entra en kernel
 Producto de llamada a sistema, interrupción o excepción
El Planificador del SO se ejecuta
 Es tiempo de cambio de contexto?
 Si, sacar de cola de listos siguiente proceso a ejecutar.
Proceso B
Rutina en assembly intercambia información de estado del
HW
 Salva el estado de proceso A en su PCB
 Restaura estado de proceso B de su PCB
 Salvar y recuperar estado, incluye CPU y adm de memoria
virtual y resets de caches
Ejecuta proceso B
OS retorna a modo usuario
Cambio de contexto en linux

Para cambio relacionado con la memoria


Include/asm/mmu_context.h
Para cambio de recursos de CPU

include/asm/system.h
• Aqui se define una macro llamada
switch_to(prev,next,last)
• Para mayor información de los detalles de esta macro
revisar
 Bovet Daniel P., Sesati Marco, “Understanding the
Linux Kernel” (2nd Edition). O'Reilly Media, Inc. 2002
Procesos en Unix


Como crear aplicaciones usando procesos?
Usando Llamadas a sistema



Fork : crea un nuevo proceso
Exec : ejecuta un programa en proceso
(varios formatos disponibles)
Kill : envia señales a procesos
• Pueden ser de término o no

Wait : espera por proceso hasta que termina
• Varios formatos
Creación de procesos en Unix


Usando llamada a sistema fork()
Básicamente, copia proceso padre



Proceso hijo obtiene un espacio de
direccionamiento igual al del padre, pero es
independiente
Proceso hijo hereda todos los archivos
abiertos del padre
Fork se comporta diferente a cualquier
llamado

Retorna dos veces
• Retorna el pid del hijo al padre
• Retorna 0 al hijo
Ejemplo fork
#include <unistd.h>
int value = 5;
int main () {
pid_t pid ;
Qué valor es impreso
en pantalla?
value = 7;
pid = fork();
if (pid == 0) { // hijo
value += 15;
}
else {
// Padre
wait (NULL); // espera a que hijo termine
printf("PADRE: value = %d\n",value );
}
}
Fork versus exec

Fork()
 Sólo permite crear nuevo proceso copiando al padre
 Como hacer que el hijo ejecute algo diferente
• Usando exec()
• Ejemplo
• Int exec( char *prog, char **argv)

Exec()
 Detiene proceso actual
 Carga programa ‘prog’ en espacio de direccionamiento
 Inicializa nuevo contexto, args para ‘prog’
 Pone PCB proceso en cola de listos
 NO CREA nuevo proceso, solo cambia lo que esta en
espacio de direcciomiento
Variaciones de exec()
int ret;
ret = execl ("/bin/ls", "ls", "-1", (char *)0);
char *env[] = { "HOME=/usr/home", "LOGNAME=home", (char *)0 };
ret = execle ("/bin/ls", "ls", "-l", (char *)0, env);
ret = execlp ("ls", "ls", "-l", (char *)0)
char *cmd[] = { "ls", "-l", (char *)0 };
ret = execv ("/bin/ls", cmd);
char *cmd[] = { "ls", "-l", (char *)0 };
ret = execvp ("ls", cmd);
Variaciones wait()
pid_t wait(int *status)
pid_t waitpid(pid_t, int *status, int
options)
Shell Unix
int main(int argc, char **argv)
{
while (1) {
char *cmd = get_next_command();
int child_pid = fork();
if (child_pid == 0) {
exec(cmd); // vea variaciones de exec
panic(“exec failed!”);
} else {
int st;
waitpid(child_pid, &st, WIFEXITED(st));
}
}
}
Comunicación entre procesos

Usando señales SIGUSR1, SIGUSR2


Ejemplo sigusuario.c
Usando Pipes

Permite la comunicación en un
sentido entre dos procesos
• Int pipe(int fds[2])
Pipe en un proceso
Proceso de usuario
write fd
read fd
kernel
pipe
-> Flujo de datos ->
Código que representa pipe en un
proceso
#include <unistd.h>
main() {
int pipefd[2], n;
char buff[100];
if(pipe(pipefd) < 0)
cout<<“error con pipe”<<endl;
cout<<“read fd = %d, write fd = %d\n”, pipefd[0],
pipefd[1]);
if(write(pipefd[1], “hola yo mismo\n”, 14) != 14)
cerr<<“error con write”<<endl;
if ((n = read(pipefd[0], buff, sizeof(buff))) <=0 )
cerr<<“error con read”<<endl;
write(1, buff, n);
}
// 1 por salida estandar stdout
Pipe en proceso padre/hijo después
de fork
Proceso hijo
Proceso padre
fork
write fd
read fd
write fd
kernel
pipe
-> Flujo de datos ->
read fd
Comunicando padre con hijo en una
dirección
Proceso hijo
Proceso padre
fork
write fd
read fd
write fd
kernel
pipe
-> Flujo de datos ->
read fd
Usando dup2

int dup2(int oldfd, int newfd);

Permite duplicar oldfd creado con otro
especificado en newfd, cerrando
newfd primero si es necesario
Ejemplo usando dup2
int main(int argc, char **argv)
{
int pipefd[2];
int pid;
pipe(pipefd);
pid = fork();
if (pid == 0){ // este es el hijo
dup2(pipefd[1], 1);
close(pipefd[1]);
cout<<" hola papa como estas ...\n";
} else {
char msg[100];
dup2(pipefd[0], 0);
close(pipefd[1]);
cin.getline(msg,100);
int st;
waitpid(pid, &st, WIFEXITED(st));
cout<<" msg en padre "<<msg<<endl;
cout<<" ahh!! me hijo se acuerda de mi\n";
}
}
Descargar

Procesos