void *hydrogen_routine(void *arg) { thread_data *t_data = (thread_data *)arg; int thread_id = t_data->t_id; // acquire lock on mutex before accessing shared memory semwait(&mutex); // if enough C is waiting, continue past barrier printf("HYDROGEN %d reached barrier.\n", thread_id); if (waiting_h >= 3 && waiting_c >= 1) { printf("~~~~ Crossed barrier, created a Methane!\n\n"); // release 4 H int i; for(i = 0; i < 3; i++) { semsignal(&sem_h); } waiting_h -= 3; semsignal(&sem_c); waiting_c--; // release lock on mutex semsignal(&mutex); } else { // not enough H or C is waiting, so wait at barrier waiting_h++; printf("Waiting Atoms -- C: %d | H: %d\n", waiting_c, waiting_h); // release lock on mutex semsignal(&mutex); semwait(&sem_h); } pthread_exit(EXIT_SUCCESS); }
static void semwait(int sem) { struct sembuf sbuf = { .sem_num = 0, .sem_op = -1, .sem_flg = 0 }; assert (semop(sem, &sbuf, 1) != -1); } static void semsignal(int sem) { struct sembuf sbuf = { .sem_num = 0, .sem_op = 1, .sem_flg = 0 }; assert (semop(sem, &sbuf, 1) != -1); } static pid_t fork_generator( int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y, int left_x, int left_y ) { pid_t child = fork(); if (child != 0) { // Parent assert (child != -1); return child; } else // Child exit(generator( sem_labyrinth, shm_stats, shm_labyrinth, top_x, top_y, left_x, left_y) ); } // Retourne la cellule qui partage le même mur. static CELL *cell_fellow(CELL *cell, WALL orientation); // Retourne l'orientation opposée d'un mur static WALL orientation_inv(WALL orientation); // Vérifie que certains murs privés ne partagent pas à présent les mêmes groupes // ou qu'ils ne sont pas devenus partagés lorsque on a lié les deux groupes. static void update_private( LABYRINTH labyrinth, CELL walls[], int *last_private, int *first_shared ); static int generator( int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y, int left_x, int left_y ) { int size = LABYRINTH_SIZE / 2; // Récupère les mémoires partagées. PARAL_STATS *stats = (PARAL_STATS *) shmat(shm_stats, NULL, 0); assert (stats != (PARAL_STATS *) -1); LABYRINTH labyrinth = (LABYRINTH) shmat(shm_labyrinth, NULL, 0); assert (labyrinth != (LABYRINTH) -1); // Retiens les murs non ouverts dans la zone du générateur (indice de la // cellule avec orientation du mur, utilise les bits dédiés au groupe // pour encoder l'indice). // Ajoute les murs non partagés à partir de la gauche et ceux partagés à // partir de la droite du vecteur. int n_walls = 2 * size * size; int last_private = -1 , first_shared = n_walls; CELL walls[n_walls]; semwait(sem_labyrinth); // Accède en lecture à des cellules partagées. for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { int top_index = (top_y + i) * LABYRINTH_SIZE + top_x + j , left_index = (left_y + i) * LABYRINTH_SIZE + left_x + j; CELL *top_cell = labyrinth + top_index , *left_cell = labyrinth + left_index; CELL top_fellow = *cell_fellow(top_cell, WALL_TOP) , left_fellow = *cell_fellow(left_cell, WALL_LEFT); // Ajoute les murs sur des cases partagées à droite, les autres // à gauche. if (is_shared(*top_cell) && is_shared(top_fellow)) walls[--first_shared] = WALL_TOP | (CELL) top_index; else walls[++last_private] = WALL_TOP | (CELL) top_index; if (is_shared(*left_cell) && is_shared(left_fellow)) walls[--first_shared] = WALL_LEFT | (CELL) left_index; else walls[++last_private] = WALL_LEFT | (CELL) left_index; } } semsignal(sem_labyrinth); // Boucle tant qu'il reste des murs à supprimer. for (;;) { semwait(sem_labyrinth); // Vérifie que les murs partagés n'ont pas été supprimés par un autre // processus et qu'ils départagent toujours deux groupes différents. for (int i = n_walls - 1; i >= first_shared; i--) { CELL wall = walls[i]; CELL index = wall & GROUP_MASK; WALL orientation = wall & WALLS_MASK; CELL *cell1 = labyrinth + index; CELL *cell2 = cell_fellow(cell1, orientation); bool can_be_removed = is_wall(*cell1, orientation) && cell_root(labyrinth, cell1) != cell_root(labyrinth, cell2); if (!can_be_removed) // Ne peut plus supprimer ce mur. walls[i++] = walls[first_shared++]; } // Sélectionne au hasard un mur dans les murs restants. int n_remaining = (last_private + 1) + (n_walls - first_shared); if (n_remaining == 0) { semsignal(sem_labyrinth); break; } int random_index = rand() % n_remaining; if (random_index <= last_private) { stats->hits++; semsignal(sem_labyrinth); // Cette partie de l'algorithme peut s'effectuer en même temps sur // différents processus : CELL wall = walls[random_index]; CELL index = wall & GROUP_MASK; WALL orientation = wall & WALLS_MASK; CELL *cell1 = labyrinth + index; CELL *cell2 = cell_fellow(cell1, orientation); CELL *root1 = cell_root(labyrinth, cell1) , *root2 = cell_root(labyrinth, cell2); // Attache toujours une cellule qui n'appartient pas à un groupe // partagé à l'autre cellule. De cette manière, la racine d'un // groupe dont au moins une cellule est partagée sera une cellule // partagée. Ceci évite également de modifier une forêt qui pourrait // être modifiée par un autre processus au même moment. if (is_shared(*root1)) cell_attach_group(root2, *root1); else cell_attach_group(root1, *root2); // Supprime le mur de la liste d'attente et des deux cellules. walls[random_index] = walls[last_private--]; // Ces deux instructions sont équivalentes à ces deux instructions: // *cell1 &= ~orientation; // *cell2 &= ~orientation_inv(orientation); // A l'exception que le compilateur garantit que ces instructions // s'exécutent de manière atomique, et permet ainsi d'éviter que // deux processus suppriment deux murs différents d'une même cellule // au même instant, ce qui engendrait une perte de l'une des deux // modifications. __sync_fetch_and_and(cell1, ~orientation); __sync_fetch_and_and(cell2, ~orientation_inv(orientation)); // Une alternative aurait été d'acquérir la sémaphore sem_labyrinth // lorsque l'on change l'orientation d'une cellule qui est sur un // bord de la zone du générateur, mais cette méthode est // considérablement plus rapide. update_private(labyrinth, walls, &last_private, &first_shared); } else { stats->misses++; int wall_index = random_index - (last_private + 1) + first_shared; CELL wall = walls[wall_index]; CELL index = wall & GROUP_MASK; WALL orientation = wall & WALLS_MASK; CELL *cell1 = labyrinth + index; CELL *cell2 = cell_fellow(cell1, orientation); CELL *root1 = cell_root(labyrinth, cell1); cell_attach_group(root1, *cell2); // Supprime le mur de la liste d'attente et des deux cellules. walls[wall_index] = walls[first_shared++]; *cell1 &= ~orientation; *cell2 &= ~orientation_inv(orientation); semsignal(sem_labyrinth); } } return EXIT_SUCCESS; }
void * recepcionista_S(void *args) { Cliente cli_ready; while(feito == 0) // enquanto estiver em funcionamento { if(work == 2){ // quando receber ordem de fecho avisa os clientes que o carro nao esta pronto if(!IsEmpty(Qmec)){ pthread_mutex_lock(&mutexDone); cli_ready = FrontAndDequeue(Qmec); pthread_mutex_unlock(&mutexDone); //informar o cliente que o carro não está terminado pthread_mutex_lock(&mutexRegis); regista(RECEPS, cli_ready.matricula, "Vou despachar o cliente com um SIGUSR2"); pthread_mutex_unlock(&mutexRegis); kill(cli_ready.id, SIGUSR2);//enviado o sinal que o carro nao esta pronto } if(!IsEmpty(Qele)){ pthread_mutex_lock(&mutexDone); cli_ready = FrontAndDequeue(Qele); pthread_mutex_unlock(&mutexDone); //informar o cliente que o carro não está terminado pthread_mutex_lock(&mutexRegis); regista(RECEPS, cli_ready.matricula, "Vou despachar o cliente com um SIGUSR2"); pthread_mutex_unlock(&mutexRegis); kill(cli_ready.id, SIGUSR2);//enviado o sinal que o carro nao esta pronto } if(!IsEmpty(Qcha)){ pthread_mutex_lock(&mutexDone); cli_ready = FrontAndDequeue(Qcha); pthread_mutex_unlock(&mutexDone); //informar o cliente que o carro não está terminado pthread_mutex_lock(&mutexRegis); regista(RECEPS, cli_ready.matricula, "Vou despachar o cliente com um SIGUSR2"); pthread_mutex_unlock(&mutexRegis); kill(cli_ready.id, SIGUSR2);//enviado o sinal que o carro nao esta pronto } if(!IsEmpty(Qpin)){ pthread_mutex_lock(&mutexDone); cli_ready = FrontAndDequeue(Qpin); pthread_mutex_unlock(&mutexDone); //informar o cliente que o carro não está terminado pthread_mutex_lock(&mutexRegis); regista(RECEPS, cli_ready.matricula, "Vou despachar o cliente com um SIGUSR2"); pthread_mutex_unlock(&mutexRegis); kill(cli_ready.id, SIGUSR2);//enviado o sinal que o carro nao esta pronto } } if(!IsEmpty(Qdone)){ // se tiver veiculos prontos pthread_mutex_lock(&mutexDone); cli_ready = FrontAndDequeue(Qdone); pthread_mutex_unlock(&mutexDone); //meter no parque pointer[posicao] = cli_ready; posicao++; //informar o cliente que o carro está no parque (pointer) pthread_mutex_lock(&mutexRegis); regista(RECEPS, cli_ready.matricula, "Vou despachar o cliente com um SIGUSR1"); pthread_mutex_unlock(&mutexRegis); kill(cli_ready.id, SIGUSR1); //enviado o sinal para tirar o carro do parque //Vou aguardar que o cliente retire o carro do parque semwait(semid); } else { if (work == 2) feito = 1; // se passar da hora de fecho e todos os veiculos prontos tiverem sido levantados, nao espera mais! } } pthread_mutex_lock(&mutexRegis); regista(RECEPS,NULL,"Boa tarde chefe e ate amanha!"); pthread_mutex_unlock(&mutexRegis); return NULL; }
int main(int argc, char** argv) { printf("bus %s started\n", argv[1]); fflush(stdout); int semid, shmid; struct Common* shared; semid = semget(getSemKey(), NUM_SEMS, 0777); shmid = shmget(getSemKey(), 0, 0); shared = (struct Common *)shmat(shmid, 0, 0); semwait(semid, SEM_GATE_EMPTY); printf("Bus %s has arrived\n", argv[1]); fflush(stdout); semsignal(semid, SEM_BUS_BOARDABLE); semwait(semid, SEM_MUTEX); time_t sleep_time = shared->departure_time - time(NULL); semsignal(semid, SEM_MUTEX); printf("Bus %s Sleeping until departure\n", argv[1]); fflush(stdout); sleep(sleep_time); semwait(semid, SEM_MUTEX); printf("Bus %s: last call for boarding\n", argv[1]); fflush(stdout); while(1) { semwait(semid, SEM_CAN_BOARD); if(shared->tickets_sold == shared->boarded) { semsignal(semid, SEM_CAN_BOARD); break; } semsignal(semid, SEM_CAN_BOARD); // wait another second to give customer // threads a chance to finish boarding sleep(1); } semwait(semid, SEM_BUS_BOARDABLE); // release passengers to the gate that were waiting for the next bus printf("Bus %s releasing next bus queue\n", argv[1]); fflush(stdout); int i; for(i=0; i<shared->next_bus_tickets; i++) { semsignal(semid, SEM_NEXT_BUS_QUEUE); } // reset the ticket variables for the next bus printf("Bus %s preparing shared variables for next bus\n", argv[1]); fflush(stdout); // if there were customers waiting for the next, next bus or beyond // release some of them for(i=0; i<shared->tickets_sold; i++) { semsignal(semid, SEM_MAX_CUSTOMERS); } shared->tickets_sold = shared->next_bus_tickets; shared->next_bus_tickets = 0; shared->departure_time += BUS_PERIOD; shared->boarded = 0; semsignal(semid, SEM_MUTEX); semsignal(semid, SEM_GATE_EMPTY); printf("Bus %s is departing\n", argv[1]); fflush(stdout); return 0; }