#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
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
int i=0;
while( i<10000 p="p"> {
if(lock())
{
mensaje->z++;
unlock();
i++;
}
//sleep(0.5);
}
}
// P3
void proceso3()
{
mensaje = reinterpret_cast
int i=0;
while( i<10000 p="p"> {
if(lock())
{
mensaje->z++;
unlock();
i++;
}
//sleep(0.5);
}
}
// P4
void proceso4()
{
mensaje = reinterpret_cast
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;
}
10000>10000>10000>4>
No hay comentarios:
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.