miércoles, 24 de octubre de 2012

Hilos En C++


#include
#include

#include
#include
#include

#include
#include
#include
#include

#include
#include

/*
 * Diagrama de precedencia:
 *
 *              inicial()
 *                 |
 *                 |
 *                /|\
 *               / | \
 *              /  |  \
 *             /   |   \
 *            /    |    \
 *           P1    P2    P3
 *            \    |    /
 *             \   |   /
 *              \  |  /
 *               \ | /
 *                \|/
 *                 |
 *                 |
 *               final()
 *
 */

union semun {
    int val;                    /* value for SETVAL */
    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
    unsigned short int *array;  /* array for GETALL, SETALL */
    struct seminfo *__buf;      /* buffer for IPC_INFO */
};

pid_t pid_hijo1;
pid_t pid_hijo2;
pid_t pid_hijo3;
pid_t pid_hijo4;

key_t key_shared;

int id_heap;
int *mini_heap = NULL;
int sem_id;

// Estructura de 100 bytes
class Mensaje
{
public:
    Mensaje()
    {
        a = 0;
        b = 0;
        c = 0;
        d = 0;
        e = 0;
        f = 0;
        g = 0;
        h = 0;
        i = 0;
        j = 0;
        k = 0;
        l = 0;
        a2 = 0;
        b2 = 0;
        c2 = 0;
        d2 = 0;
        e2 = 0;
        f2 = 0;
        g2 = 0;
        h2 = 0;
        i2 = 0;
        j2 = 0;
        k2 = 0;
        l2 = 0;
        z = 0;
    }

    int a;
    int b;
    int c;
    int d;
    int e;
    int f;
    int g;
    int h;
    int i;
    int j;
    int k;
    int l;
    int a2;
    int b2;
    int c2;
    int d2;
    int e2;
    int f2;
    int g2;
    int h2;
    int i2;
    int j2;
    int k2;
    int l2;
    int z;
};

Mensaje * mensaje;

// plantilla para liberar con más robustez
template
void delete_ptr(T* ptr)
{
    if(ptr)
    {
        delete ptr;
        ptr = NULL;
    }
}

// iniciar semaforo compartido (solo el proceso padre)
int set_semvalue(void)
{
    union semun sem_union;

    sem_union.val = 1;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
    return(1);
}

// liberar semaforo compartido (solo el proceso padre)
void del_semvalue(void)
{
    union semun sem_union;
   
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        fprintf(stderr, "Failed to delete semaphore\n");
}

// intenta bloquear el semaforo compartido
bool lock(void)
{
    bool retorno = false;

    struct sembuf sem_b;
   
    sem_b.sem_num = 0;
    sem_b.sem_op = -1; /* P() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        //fprintf(stderr, "semaphore_p failed\n");
        retorno = false;
    }
    else
        retorno = true;
   
    return retorno;
}

// intenta liberar el semaforo compartido
bool unlock(void)
{
    bool retorno = false;

    struct sembuf sem_b;
   
    sem_b.sem_num = 0;
    sem_b.sem_op = 1; /* V() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        //fprintf(stderr, "semaphore_v failed\n");
        retorno = false;
    }
    else
        retorno = true;
       
    return retorno;
}

// El proceso padre crea la memoria compartida y el semaforo
void inicial()
{
    id_heap = shmget (key_shared, sizeof(int)*100, 0777 | IPC_CREAT);
    if (id_heap == -1)
    {
        std::cout << "No consigo Id para memoria compartida" << std::endl;
        exit (0);
    }

    mini_heap = (int *)shmat (id_heap, (char *)0, 0);
    if (mini_heap == NULL)
    {
        std::cout << "No consigo memoria compartida" << std::endl;
        exit (0);
    }
   
    std::cout << "Memoria compartida creada" << std::endl;
   
    ///////// SEMAFORO
   
    sem_id = semget(key_shared, 1, 0777 | IPC_CREAT);
   
    if(!set_semvalue())
    {
        std::cout << "Error al iniciar semáforo" << std::endl;
        exit (0);
    }
   
    ////////////////////
   
    // Memoria dinamica local
    mensaje = new Mensaje();
    mensaje->z = 0;
   
    // copiar a zona compartida
    memcpy (mini_heap, mensaje, sizeof(*mensaje));
   
    // liberamos la copia local
    delete_ptr(mensaje);
}

// el proceso padre libera las zonas compartidas
void final()
{
    int estadoHijo;
   
    for(int i=0 ; i<4 i="i" p="p">    {
        wait (&estadoHijo);

        if (WIFEXITED(estadoHijo) != 0)
        {
            assert(101 <= WEXITSTATUS(estadoHijo) && WEXITSTATUS(estadoHijo) <= 104);
            //printf ("Padre : Mi hijo ha salido. Devuelve %d\n", WEXITSTATUS(estadoHijo));
        }
    }
    /////////////////////////////////////////////////////////
   
    mensaje = reinterpret_cast(mini_heap);
    std::cout << "mensaje->z = " << mensaje->z << std::endl;
   
    // se espera 10000
    assert(mensaje->z == 10000);
   
    //////////////////////////////////////////////////////////
   
    del_semvalue();
   
    //////////////////////////////////////////////////////////
    // liberamos memoria compartida
    shmdt ((char *)mini_heap);
    shmctl (id_heap, IPC_RMID, (struct shmid_ds *)NULL);
   
    std::cout << "Memoria compartida liberada" << std::endl;
}

// los procesos hijos se asocian a la zona compartida y a su semaforo
void inicia_proceso_hijo()
{
    std::cout << "Asociandose a la memoria compartida" << std::endl;

    id_heap = shmget (key_shared, sizeof(int)*100, 0777 );
    if (id_heap == -1)
    {
        std::cout << "No consigo Id para memoria compartida" << std::endl;
        exit (0);
    }

    mini_heap = (int *)shmat (id_heap, (char *)0, 0);
    if (mini_heap == NULL)
    {
        std::cout << "No consigo memoria compartida" << std::endl;
        exit (0);
    }
   
    //////////////////////////////////////////////////////
   
    // asociarse al semaforo ya creado
    sem_id = semget(key_shared, 1, 0777);
}

// Los procesos hijso se desasocian de la memoria compartida al salir.
void termina_proceso_hijo()
{
    std::cout << "Desasociandose a la memoria compartida" << std::endl;
    if (id_heap != -1)
        shmdt ((char *)mini_heap);
}

// P2
void proceso2()
{
    mensaje = reinterpret_cast(mini_heap);
   
    int i=0;
    while( i<10000 p="p">    {
        if(lock())
        {
            mensaje->z++;
            unlock();
            i++;
        }
        //sleep(0.5);
    }
}

// P3
void proceso3()
{
    mensaje = reinterpret_cast(mini_heap);
   
    int i=0;
    while( i<10000 p="p">    {
        if(lock())
        {
            mensaje->z++;
            unlock();
            i++;
        }
        //sleep(0.5);
    }
}

// P4
void proceso4()
{
    mensaje = reinterpret_cast(mini_heap);
   
    int i=0;
    while( i<10000 p="p">    {
        if(lock())
        {
            mensaje->z--;
            unlock();
            i++;
        }
        //sleep(0.5);
    }
}

/*
 * FIXME: Lo suyo es hacer los fork() con un for(;;) en función del
 * número de cores, que se sabe facilmente con OpenMP:
 *
 *  num_cores = omp_get_num_procs();
    max_threads = omp_get_max_threads();
 *
 */
int main()
{
    key_shared = ftok ("/bin/ls", 33);
    if (key_shared == -1)
    {
        std::cout << "No consigo clave para memoria compartida" << std::endl;
        exit(0);
    }
   
    pid_hijo1 = fork();
    if (pid_hijo1 > 0)
    {      
        inicial();
       
        pid_hijo2 = fork();
        if(pid_hijo2 > 0)
        {
            pid_hijo3 = fork();
            if(pid_hijo3 > 0)
            {
                pid_hijo4 = fork();
                if(pid_hijo4 > 0)
                {
                    // para hacer más procesos secuencialmente
                }
                else
                {
                    inicia_proceso_hijo();
                    proceso4();
                    termina_proceso_hijo();
                    exit (104);  
                }
            }
            else
            {
                inicia_proceso_hijo();
                proceso3();
                termina_proceso_hijo();
                exit (103);
            }
        }
        else
        {
            inicia_proceso_hijo();
            proceso2();
            termina_proceso_hijo();
            exit (102);
        }
       
        final();
    }
    else
    {
        exit (101);
    }
   
    return 0;
}

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.