miércoles, 19 de diciembre de 2012

Multi programacion



4.    Multiprogramación

Es la técnica que permite que dos o más procesos ocupen la misma unidad de memoria principal y que sean ejecutados al “mismo tiempo” en la unidad central de proceso o CPU.

Aporta las siguientes ventajas:
·         Varios procesos en ejecución.
·         Permite el servicio interactivo simultáneo a varios usuarios de manera eficiente.
·         Aprovecha los tiempos que los procesos pasan esperando a que se completen sus operaciones de E/S.
·         Aumenta el uso de la CPU.
·         Las direcciones de los procesos son relativas, el programador no se preocupa por saber en dónde estará el proceso dado que el sistema operativo es el que se encarga de convertir la dirección lógica en física.


4.1.                   Partición de tamaño fijo
Si tenemos un sistema operativo mono usuario  la CPU aprovecharía  este aprovecharía mínimamente el rendimiento ya que al ser un único proceso por vez, si el sistema tiene  una entrada o salida, el tiempo de espera del sistema aumentaría considerablemente.  En el grafico de continuación se verá  una comparativa entre un sistema trabajando con un computo intensivo y un sistema ralentizado por entradas y salidas
Lo que se mejoro mediante “multiprogramación” es que esos tiempos de espera fuera utilizado por otros usuarios del sistema, por ejemplo ese tiempo que el sistema está esperando puede ser utilizado para procesos de otro usuario, lo cual conlleva que en memoria principal deba haber varios programas de forma simultánea.
La programación de tamaño fijo consiste  en crear una ilusión de simultaneidad  dividiendo la memoria principal en bloques de tamaño fijo el cual crea una ilusión de simultaneidad
Para saber  en qué parte de la memoria se encontraba cada programa se encargaban cada  partición relacionarla con un programa y dividirlo en sus procesos 
Para el SO. Resulta sencillo ya que todas las instrucciones de un mismo programan van a estar en la misma ubicación.


4.1.1.                       Carga absoluta y carga con reubicación
La reubicación de una partición de tamaño fijo se utiliza por ejemplo cuando la partición que se está utilizando se ha quedado pequeña y el programa necesita una partición de tamaño mas grande ya que al ser las particiones de tamaño fijo no se pueden ampliar .
Este procedimiento es más complejo ya que hay que tener en cuenta el tamaño de todas las particiones del sistema (en memoria principal) y de cuales están libres en cada ciclo, pero también tiene una gran ventaja que le da al sistema una mayor flexibilidad para distintos tipos de procesos.
4.1.2.                       Sistema de protección

Cuando se usa la asignación contigua de memoria la protección suele implementarse con varios registros de limites.

Los extremos de una partición pueden ir delineados con 2 registros o, también, indicados por el limite inferior o superior y el tamaño de la partición.

En el caso de que vayan delineados por 2 registros:
En el caso de que vayan indicados:


4.1.3.                       Inconveniente de la fragmentación

La fragmentación en el almacenamiento es algo que ocurre en cualquier sistema de independientemente de cómo se organice la memoria.

Normalmente este inconveniente se produce cuando:
·         Los trabajos del usuario no llenan completamente sus particiones designadas.
·         Una partición permanece sin usar porque es demasiado pequeña para alojar un trabajo que está en espera.


4.2.                   Partición de tamaño variable

Cuando se usa una partición de tamaño variable los procesos ocupan tanto espacio como necesitan, pero sin superar el espacio disponible en la memoria.

En particiones variables, no hay limites fijos de memoria, luego la partición de un trabajo es un propio tamaño.

Se consideran “esquemas de asignación contigua”, ya que un programa debe ocupar las posiciones adyacentes de almacenamiento.

Una vez que los procesos terminan dejan disponibles espacios de memoria principal entre los cuales hay otros procesos, estos se pueden denominar “agujeros”.

Estos agujeros pueden ser usados por otros procesos o trabajos y que cuantos estos terminan dejan otros agujeros más pequeños. Esto de forma sucesiva provoca que los agujeros sean cada vez más numerosos provocando un mayor desperdicio de memoria.

Estos agujeros se pueden combinar o fusionar, de forma que cuando un proceso termina y el almacenamiento que libera tiene limites con otros agujeros, combina o fusiona con todos los agujeros adyacentes formando uno solo.

martes, 11 de diciembre de 2012

Trabajo voluntario de concurrencia - Fumadores SO 12/13

He aquí el pseudocódigo de la práctica voluntaria:




-- Fumadores --

-- Definición de tipos --

definir TIPOS 3
definir ITERACIONESF 20
definir ITERACIONESP 50
definir FUMADORES    3

-- Variables globales --

entero         fumadores[TIPOS][TIPOS];
entero         mesa[TIPOS];
caracter     traduccion[TIPOS][100]={"cerillas","papel","tabaco"};


-- Semaforos --

semaforo mutex,necesidad,producido;

-- Prototipo de funciones --

vacio *fumador(vacio *id);
vacio *productor();
vacio cogerLoQueNecesito(entero id);

-- Programa pincipal --

entero principal()
{
    hilo hiloProductor[1];
    hilo hilosFumadores[FUMADORES];
    entero i,id[FUMADORES];estado;
   
    variableExterna semaforo mutex, necesidad, producido;
    variableExterna entero fumadores[TIPOS][TIPOS],mesa[TIPOS];
   
    random(tiempo(NULO));
   
    -- Inicializacion de variables --
    -- FUMADOR 0
    fumadores[0][0]=0; fumadores[0][1]=25; fumadores[0][2]=25;
    -- FUMADOR 1
    fumadores[1][0]=25; fumadores[1][1]=0; fumadores[1][2]=25;
    -- FUMADOR 2
    fumadores[2][0]=25; fumadores[2][1]=25; fumadores[2][2]=0;
    -- MESA
    mesa[0]=0; mesa[1]=0; mesa[2]=0;

    iniciar_semilla(&mutex,1,0);
    iniciar_semilla(&necesidad,1,1);
    iniciar_semilla(&producido,1,0);
   
    Si ((estado = crear_hilo(&hiloProductor[0],Nulo,productor,Nulo)))
    Salir (estado);
   
    Para(i=0;i<FUMADORES;i++)
    {
        id[i]=i;
        Si ((estado = crear_hilo(&hilosFumadores[i],Nulo,fumador,(vacio *) &id[i])))
        Salir (estado);
    }
   
    union_hilo(hilosFumadores[i], Nulo);
   
    Para(i=0;i<FUMADORES;i++)
    {
        union_hilo(hilosFumadores[i],Nulo);
    }
    devolver(0);
}

vacio *fumador(vacio *id)
{
    entero *nombre, i, j, vez=0;
   
    variableExterna semaforo mutex,necesidad,producido;
   
    nombre=(int *) id;
   
    Escribir("Comienza el fumador *nombre");
   
    Para(i=0;i<ITER;i++)
    {
        semaforoEsperar(&producido);
        cogerLoQueNecesito(*nombre);
       
        mientras(fumador[*nombre][0]>0 && fumadores[*nombre][1]>0 && fumadores[*nombre][2]>0)
        {
            Para(j=0;j<TIPOS;j++)
            {
                fumadores[*nombre][j]-=1;
                vez++;
                Escribir("El fumador *nombre esta fumando vez");
            }
        }
       
        dormir(2);
       
        Escribir("El fumador *nombre necesita coger cosas");
        semaforoEnviar(&necesidad);
       
       
           
    }
    hiloSalir(Nulo);
}
   
vacio *productor()
{

    entero i,tipo,U;
   
    variableExterna semaforo mutex,necesidad,producido;
    variableExterna entero mesa[TIPOS];
    variableExterna caracter traduccion[TIPOS][100];
   
    para(i=0;i<ITERACIONESP;i++)
    {
        semaforoEsperar(&necesidad);
        semaforoEsperar(&mutex);
       
        tipo=random()%3;
        U=random()%10;
        mesa[tipo]+=U;
        Escribir("Productor produjo traduccion[tipo] --> U");
       
        semaforoEnviar(&mutex);
        semaforoEnviar(&producido);
    }
    hiloSalir(Nulo);
}

vacio cogerLoQueNecesito(entero id)
{
    entero j, cogido=;
   
    variableExterna semaforo mutex, producido;
    variableExterna mesa[TIPOS], fumadores[TIPOS][TIPOS];
    variableExterna caracter traduccion[TIPOS][100];
   
    semillaEsperar(&mutex);
    Para(j=0;j<TIPOS;j++)
    {
        Si(fumadores[id][j]==0)
        {
            Si(mesa[0]>0)
            {
                fumadores[id][j]=mesa[j];
                Escribir("El Fumador (id) cogió mesa[j] de traduccion[j]");
                mesa[j]=0;
                cogido=1;
            }
        }
    }
    semaforoEnviar(&mutex);
}


He aquí el código en C de los fumadores:



//Ejercicio voluntario fumadoress !!

//Librerias nesesarias
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>

//DEFINES
#define TIPOS 3 //cerillas-tabaco-papel
#define ITER 20 //iteraciones del fumador
#define ITERP 50 //Iteraciones del productor
#define F 3 //Numero de fumadores

//Variables globales
int f[TIPOS][TIPOS];
int mesa[TIPOS];
char traducion[TIPOS][100]={"serillas", "Papel", "Tabaco"};

//Semaforos
sem_t mutex,nesesidad,producido;


//Prototipos de funciones
void *fumador(void *id);
void *productor();
void cojerLoQueNesesito(int id);

//Programa principal
int main()
{
    pthread_t hiloP[1];
    pthread_t hilosF[F];
    int i,id[F],status;

    extern sem_t mutex, nesesidad, producido;
    extern int f[TIPOS][TIPOS],mesa[TIPOS];

    srand(time(NULL));

    // **** Inicializaci�n de variables ****
    //FUMADOR 0
    f[0][0]=0; f[0][1]=25; f[0][2]=25;
    //FUMADOR 1
    f[1][0]=25; f[1][1]=0; f[1][2]=25;
    //FUMADOR 2
    f[2][0]=25; f[2][1]=25; f[2][2]=0;
    //mesa
    mesa[0]=0; mesa[1]=0; mesa[2]=0;

    //SEMAFOROS
    sem_init(&mutex, 1, 0);
    sem_init(&nesesidad, 1, 1);
    sem_init(&producido, 1, 0);

    //hilo productor
    if ((status = pthread_create(&hiloP[0], NULL, productor, NULL)))
        exit(status);

    for(i=0;i<F;i++)
    {   
        id[i]=i;
        if ((status = pthread_create(&hilosF[i], NULL, fumador, (void *) &id[i])))
            exit(status);
    }

    //esperar hasta finalizar el productor
    pthread_join(hiloP[0], NULL);

   
    //esperar hasta finalizar los hilos fumadores
    for (i = 0; i < F; i++)
    {
        pthread_join(hilosF[i], NULL);
    }

    return (0);
}
//funcion para los fumadores
void *fumador(void *id)
{
    int *nombre, i, j, vez=0;

    extern sem_t mutex, nesesidad, producido;
   
    nombre=(int *) id;

    printf("\nComienza el fumador %d", *nombre);

    for(i=0;i<ITER;i++)
    {
        sem_wait(&producido); //Espera hasta que el productor haya producido algo

        //comprueba que es lo que nesesita y si nesesita algo lo coje
        cojerLoQueNesesito(*nombre);


        while(f[*nombre][0]>0 &&f[*nombre][1]>0 &&f[*nombre][2]>0) //fuma mientras tenga
        {
            for(j=0;j<TIPOS;j++)//Gasta una unidad de cada cosa           
                f[*nombre][j]-=1;
            vez++;
            printf("\nEl fumador %d esta fumado %d", *nombre, vez);
        }

        //ha este punto solo se llega si no se tiene nada mas qu fumar
        sleep(2);
        printf("\nElfumador %d nesesita coger cosas", *nombre);

        sem_post(&nesesidad); //Espera hasta que el productor haya producido algo
    }
    pthread_exit(NULL);
}

//funcion para el poductor
void *productor()
{
    int i,tipo,U;

    extern sem_t mutex, nesesidad, producido;
    extern int mesa[TIPOS];
    extern char traducion[TIPOS][100];

    for(i=0;i<ITERP;i++)
    {
        sem_wait(&nesesidad);//Espera ha que el fumador nesesite algo
        sem_wait(&mutex);

        tipo=rand() %3;
        U=rand() %10;
        mesa[tipo]+=U;   
        printf("\nProductor produjó %s --> %d", traducion[tipo], U);

        sem_post(&mutex);
        sem_post(&producido);//Indica que ya hay nuevas cosas producidas
    }

    pthread_exit(NULL);
}

//Esta funcion solo coje lo que el fumador nesesita
void cojerLoQueNesesito(int id)
{
    int j, cojido=0;

    extern sem_t mutex, producido;
    extern int mesa[TIPOS], f[TIPOS][TIPOS];
    extern char traducion[TIPOS][100];

    sem_wait(&mutex);
    for(j=0;j<TIPOS;j++)
    {
        if(f[id][j]==0)
        {
            if(mesa[0]>0)
            {
                f[id][j]=mesa[j];
                printf("\n\nEl Fumador %d cojió %d de %s ", id, mesa[j], traducion[j]);
                mesa[j]=0;
                cojido=1;
            }
        }
    }
    sem_post(&mutex);
}