MUP1+Øvelse+4.2+ParkALot

toc =Øvelse 4.2=

Opgave 1

 * 1) BIL: En bil kører op til porten og beder om at få den åbnet
 * 2) PORT: Porten åbner og sender besked til bilen når porten er helt åben
 * 3) BIL: Bilen kører nu igennem og sender besked til porten når den er helt igennem
 * 4) PORT: Porten lukker

Opgave 2
Vi skal synkronisere flere tråde sådan at det kommer til at følge ovenstående rækkefølgen. Det ville være idelt at kunne bruge et binær semaphore men det er desværre ikke understøttet, så i stedet bruger vi et par tælle semaphorer til opgaven.

code format="cpp" const int TOTAL_CARS = 3; int parkingLot = 0; sem_t entryOpenReq, entryAck, entryCloseReq, exitOpenReq, exitAck, exitCloseReq; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* entryGuardThread(void *n) {   while (1) {       sem_wait(&entryOpenReq); // Wait for open door request std::cout << "The entry door is now open!" << std::endl; // Door is open sem_post(&entryAck); // Wait for the car to pass through sem_wait(&entryCloseReq); std::cout << "The entry door is now closed!" << std::endl; }   return 0; }

void* exitGuardThread(void *n) {   while (1) {       sem_wait(&exitOpenReq); // Wait for open door request std::cout << "The exit door is now open!" << std::endl; // Door is open sem_post(&exitAck); // Wait for the car to pass through sem_wait(&exitCloseReq); std::cout << "The exit door is now closed!" << std::endl; }   return 0; }

void* carThread(void *carNr) {   int i = (int)carNr + 1; while (true) {		// Car drives up to the door std::cout << "Car #" << i << " drives up to the gate" << std::endl; sem_post(&entryOpenReq); // Request open door // Drive in		sem_wait(&entryAck); pthread_mutex_lock(&mutex); ++parkingLot; pthread_mutex_unlock(&mutex); std::cout << "Car #" << i << " parks, there's " << parkingLot << " cars parked." << std::endl; sem_post(&entryCloseReq); // Car has passed through the door

usleep(rand % 5000 + 1);

std::cout << "Car #" << i << " drives up to the exit gate" << std::endl; sem_post(&exitOpenReq); // Drive out sem_wait(&exitAck); pthread_mutex_lock(&mutex); --parkingLot; pthread_mutex_unlock(&mutex); std::cout << "Car #" << i << " exits, there's " << parkingLot << " cars parked." << std::endl; sem_post(&exitCloseReq); // Car has passed through the door

usleep(rand % 5000 + 1); }   return 0; }

int main {   sem_init(&entryOpenReq,0,0); sem_init(&entryAck,0,0); sem_init(&entryCloseReq,0,0); sem_init(&exitOpenReq,0,0); sem_init(&exitAck,0,0); sem_init(&exitCloseReq,0,0);

pthread_t entryGuard; pthread_t exitGuard; pthread_create(&entryGuard, NULL, entryGuardThread, NULL); pthread_create(&exitGuard, NULL, exitGuardThread, NULL);

pthread_t cars[TOTAL_CARS]; for (int i = 0; i < TOTAL_CARS; ++i) { pthread_create(&cars[i], NULL, carThread, (void*)i); }

void* ret[TOTAL_CARS+2]; int k;   for (k = 0; k < 3; ++k) { pthread_join(cars[k], &ret[k]); }   pthread_join(entryGuard, &ret[k++]); pthread_join(exitGuard, &ret[k++]); return EXIT_SUCCESS; }

code Det er vigtigt at have en mutex rundt om variablen parkingLot da vores synkronisering ikke sikre atomisk adgang til variablen. Vi har valgt at bruge 3 tælle semaphorer til at løse problemet, i stedet for 2 som i eksemplet i slidene, da 2 semaphore ikke er sikkert nok. Da vi ikke vil kunne forhindre at en ny bil kommer og låser op for den første semaphore inden den bliver brugt i 3. led. (lidt svært at forklare) Men hvis led 1 og 3 bruger samme semaphore kan en ny tråd komme og låse op for det 3. led via led 1.

Udskrift: code Car #1 drives up to the gate The entry door is now open! Car #2 drives up to the gate Car #2 parks, there's 1 cars parked. The entry door is now closed! The entry door is now open! Car #3 drives up to the gate Car #3 parks, there's 2 cars parked. The entry door is now closed! The entry door is now open! Car #1 parks, there's 3 cars parked. The entry door is now closed! Car #2 drives up to the exit gate The exit door is now open! Car #3 drives up to the exit gate Car #3 exits, there's 2 cars parked. The exit door is now closed! The exit door is now open! Car #2 exits, there's 1 cars parked. The exit door is now closed! Car #1 drives up to the exit gate The exit door is now open! Car #1 exits, there's 0 cars parked. The exit door is now closed! code En lidt uventet opførsel er at så snart porten er åben kan en hvilken som helst bil kører igennem. Men det giver mening kode-mæssigt og det er et abstrakt eksempel.

Opgave 3
Nu skal der tilføjes et krav mere. Der må kun lukkes biler ind hvis der er plads på parkeringspladsen. Det gøres via to tælle semaphorer. Hvor den ene holder styr på antal frie pladser tilbage og den anden har styr på antal brugte pladser. Antal frie pladser initialiseres til antal parkerings båse der er og hver gang en bil parker bliver den talt én ned, og det modsatte for antal brugte pladser. code format="cpp"
 * 1) include 
 * 2) include 
 * 3) include
 * 4) include 

const int LOT_SIZE = 10; const int TOTAL_CARS = 5; int parkingLot = 0; sem_t entryOpenReq, entryAck, entryCloseReq, exitOpenReq, exitAck, exitCloseReq, emptyParkingSpaces, usedParkingSpaces; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* entryGuardThread(void *n) {   while (1) {       sem_wait(&entryOpenReq); // Wait for open door request std::cout << "The entry door is now open!" << std::endl; // Door is open sem_post(&entryAck); // Wait for the car to pass through sem_wait(&entryCloseReq); std::cout << "The entry door is now closed!" << std::endl; }   return 0; }

void* exitGuardThread(void *n) {   while (1) {       sem_wait(&exitOpenReq); // Wait for open door request std::cout << "The exit door is now open!" << std::endl; // Door is open sem_post(&exitAck); // Wait for the car to pass through sem_wait(&exitCloseReq); std::cout << "The exit door is now closed!" << std::endl; }   return 0; }

void* carThread(void *carNr) {   int i = (int)carNr + 1; while (true) {		sem_wait(&emptyParkingSpaces); // Car drives up to the door std::cout << "Car #" << i << " drives up to the gate" << std::endl; sem_post(&entryOpenReq); // Request open door // Drive in		sem_wait(&entryAck); pthread_mutex_lock(&mutex); ++parkingLot; pthread_mutex_unlock(&mutex); std::cout << "Car #" << i << " parks, there's " << parkingLot << " cars parked." << std::endl; sem_post(&entryCloseReq); // Car has passed through the door sem_post(&usedParkingSpaces);

usleep(rand % 5000 + 1);

sem_wait(&usedParkingSpaces); std::cout << "Car #" << i << " drives up to the exit gate" << std::endl; sem_post(&exitOpenReq); // Drive out sem_wait(&exitAck); pthread_mutex_lock(&mutex); --parkingLot; pthread_mutex_unlock(&mutex); std::cout << "Car #" << i << " exits, there's " << parkingLot << " cars parked." << std::endl; sem_post(&exitCloseReq); // Car has passed through the door sem_post(&emptyParkingSpaces);

usleep(rand % 5000 + 1); }   return 0; }

int main {   sem_init(&entryOpenReq,0,0); sem_init(&entryAck,0,0); sem_init(&entryCloseReq,0,0); sem_init(&exitOpenReq,0,0); sem_init(&exitAck,0,0); sem_init(&exitCloseReq,0,0); sem_init(&emptyParkingSpaces, 0, LOT_SIZE); sem_init(&usedParkingSpaces, 0, 0);

pthread_t entryGuard; pthread_t exitGuard; pthread_create(&entryGuard, NULL, entryGuardThread, NULL); pthread_create(&exitGuard, NULL, exitGuardThread, NULL);

pthread_t cars[TOTAL_CARS]; for (int i = 0; i < TOTAL_CARS; ++i) { pthread_create(&cars[i], NULL, carThread, (void*)i); }

void* ret[TOTAL_CARS+2]; int k;   for (k = 0; k < 3; ++k) { pthread_join(cars[k], &ret[k]); }   pthread_join(entryGuard, &ret[k++]); pthread_join(exitGuard, &ret[k++]); return EXIT_SUCCESS; } code trækker én fra emptyParkingSpaces og blokere når den når 0, og lægger én til. Dvs. der bliver blokeret hvis man prøver at parkere en bil på en fuld parkingsplads.

blokere hvis man prøver at kører en bil ud fra en tom parkeringsplads. Hvilket jo heller ikke giver nogen form for mening. Faktisk kunne denne semaphore godt være udeladt da vores trådsynkronisering sikre at en bil ikke kan kører ud før den er kommet ind.

Udskrift: code Car #1 drives up to the gate Car #2 drives up to the gate Car #3 drives up to the gate Car #4 drives up to the gate Car #5 drives up to the gate The entry door is now open! Car #1 parks, there's 1 cars parked. The entry door is now closed! The entry door is now open! Car #2 parks, there's 2 cars parked. The entry door is now closed! The entry door is now open! Car #3 parks, there's 3 cars parked. The entry door is now closed! The entry door is now open! Car #4 parks, there's 4 cars parked. The entry door is now closed! The entry door is now open! Car #5 parks, there's 5 cars parked. The entry door is now closed! Car #2 drives up to the exit gate Car #4 drives up to the exit gate Car #3 drives up to the exit gate Car #5 drives up to the exit gate The exit door is now open! Car #2 exits, there's 4 cars parked. The exit door is now closed! The exit door is now open! Car #4 exits, there's 3 cars parked. The exit door is now closed! The exit door is now open! Car #3 exits, there's 2 cars parked. The exit door is now closed! The exit door is now open! Car #5 exits, there's 1 cars parked. The exit door is now closed! Car #1 drives up to the exit gate The exit door is now open! Car #1 exits, there's 0 cars parked. The exit door is now closed! code Som det kan ses så kommer antalt af parkerede biler ikke over parkeringspladens størrelse, så det virker!

=Hvad har vi lært?=
 * Vi har lært at bruge et tælle semaphore til at synkronisere tråde.
 * Vi har lært at løse et producer-consumer problem via tælle semaphore.

Tip: Det er en stor hjælp at tænke på take og release funktionerene som inc(++var) og dec(--var) og at 0 blokere, i stedet for at //take// tager en semaphore, når der skal forståes hvordan det skal blokere for hinanden.