MUP1+Øvelse+5.2

toc =Inter-thread communication using message queues in Linux II=

Opgave 1
Vi skal lave 2 tråd funktioner som venter på indput fra en besked kø og udskriver resultat til konsollen.

airspeedHdl
code format="cpp" void *airspeedHdl(void *dummy) {	key_t key = msgget(INTERPRETER_2_AIRSPEED_MSGQ, 0666 | IPC_CREAT); AirspeedMsg data; while (1) {		if (MessageHandling::receiveMsg(key, data) >= 0) cout << "Airspeed set to: " << data.getSpeed << endl; else reportError("receive airspeed"); sem_post(&printSem); }	return 0; } code

headingHdl
code format="cpp" void *headingHdl(void *dummy) {	key_t key = msgget(INTERPRETER_2_HEADING_MSGQ, 0666 | IPC_CREAT); HeadingMsg data; while (1) {		if (MessageHandling::receiveMsg(key, data) >= 0) cout << "Heading set to: " << data.getHeading << endl; else reportError("receive heading"); sem_post(&printSem); }	return 0; } code Begge funktioner starter en besked kø som de så begynder at lytte på, receiveMsg er en blocking funktion så den kommer ikke videre før den får noget indput eller fejler grumt. Hvis den fejler skriver vi fejlen ud ellers skriver vi beskeden ud og releaser en print semaphore, mere om den senere.

Opgave 2
Nu skal vi lave en tråd funktion mere som igen venter på indput fra en besked kø, hvorefter den fortolker det og sender det videre i den passende besked kø.

interpreter
code format="cpp" void *interpreter(void *dummy) {	key_t inputKey = msgget(INPUT_2_INTERPRETER_MSGQ, 0666 | IPC_CREAT); key_t headKey = msgget(INTERPRETER_2_HEADING_MSGQ, 0666 | IPC_CREAT); key_t airKey = msgget(INTERPRETER_2_AIRSPEED_MSGQ, 0666 | IPC_CREAT); InputMsg data; while (1) {		if (MessageHandling::receiveMsg(inputKey, data) >= 0) {			if (data.getInputType == InputMsg::AIRSPEED) {				AirspeedMsg speed; speed.setSpeed(data.getInputValue); MessageHandling::sendMsg(airKey, speed); }			else if (data.getInputType == InputMsg::HEADING) {				HeadingMsg heading; heading.setHeading(data.getInputValue); MessageHandling::sendMsg(headKey, heading); }			else cout << "DØD BABY!" << endl; } else reportError("interpreter"); }	return 0; } code Vi opretter de respektive køer hvis de ikke allerede er oprettet, hvis de er får vi blot køens ID. Så tjekker vi hvilken indput besked (InputMsg) type vi har fået og sender den videre i den rigtige kø og med den rigtige wrapper.

Opgave 3
Denne tråd funktion skal efterspørge (//What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit?//) og tage imod bruger indput hvorefter den skal udføre den korrekt handling. Et 'A' skal give brugeren mulighed for at indtaste "airspeed", 'H' for "heading" og 'Q' for at afsluttet programmet.

inputHdl
code format="cpp" void *inputHdl(void *quitSemId) {	key_t key = msgget(INPUT_2_INTERPRETER_MSGQ, 0666 | IPC_CREAT); char input; InputMsg data; while (1) {		cout << "What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? "; cin >> input; if (input == 'A' || input == 'a') {			int speed; do { cout << "Enter airspeed between 100 and 800: "; cin >> speed; if (cin.fail) {					cout << "Please type a number" << endl; cin.clear; cin.ignore(numeric_limits ::max, '\n'); continue; }			} while (speed < 100 || speed > 800); data.setInputType(InputMsg::AIRSPEED); data.setInputValue(speed); if (MessageHandling::sendMsg(key, data) != 0) reportError("send airspeed"); }		else if (input == 'H' || input == 'h') {			int heading; do { cout << "Enter heading between 0 and 360: "; cin >> heading; if (cin.fail) {					cout << "Please type a number" << endl; cin.clear; cin.ignore(numeric_limits ::max, '\n'); continue; }			} while (heading < 0 || heading > 360); data.setInputType(InputMsg::HEADING); data.setInputValue(heading); if (MessageHandling::sendMsg(key, data) != 0) reportError("send heading"); } else if (input == 'Q' || input == 'q') break; else {			cout << "DIN MOR!" << endl; continue; }		sem_wait(&printSem); }	sem_post((sem_t*)quitSemId); return 0; } code Først opretter vi en besked kø til at fylde vores bruger handlinger ind i, hvorefter vi efterspørger indput og behandler det ved at pakke data ned i en container klasse InputMsg som bliver sendt ud til vores indput fortolker kø. Hvis alt går godt kommer vi ned til en synkroniserings (printSem) semaphore hvor tråden bliver sat til at vente på at fortolker køen bliver tømt, behandlet og sendt ud til vores printer tråde som så låser op for semaphoren når de har printet. Skulle brugeren ønske at afsluttet programmet hopper vi blot ud af vores hvor vi låser op for en semaphore som vores main står og venter på, hvorefter main så rydder op og terminere.

Opgave 4
Hele projektet har en del filer, så her er alle filerne samlet:

Output
code What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? a Enter airspeed between 100 and 800: 22 Enter airspeed between 100 and 800: 99 Enter airspeed between 100 and 800: 100 Airspeed set to: 100 What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? A Enter airspeed between 100 and 800: 500 Airspeed set to: 500 What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? H Enter heading between 0 and 360: 1 Heading set to: 1 What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? h Enter heading between 0 and 360: -1 Enter heading between 0 and 360: 200 Heading set to: 200 What do you wish to set: (A)irspeed, (H)eading or 'Q' to quit? q ERROR: main - pthread_cancel 0:Success Good bye... code Skulle man have lyst til at tjekke hvilke besked køer der er oprettet mens programmet kører kan man gøre det via kommandoen. Sådan så det ud ved én af vores kørsler. code stud@ubuntu:~$ ipcs -q

-- Message Queues key       msqid      owner      perms      used-bytes   messages 0x000000c8 196608    stud       666        0            0 0x000000ca 229377    stud       666        0            0 0x000000c9 262146    stud       666        0            0 code