I3MUP1+Exercise+5

toc =LAB Exercise 5.1= //In this exercise you will learn the basics of thread communication in Linux using System V IPC message// //queues. You will create a system consisting of two threads that communicate, one sending information that// //the other receives. This will give you insight into how to create message queues and how to send, wait for,// //and receive data in a message queue.//

Exercise 5.1.1 & 5.1.2
For this exercise, we create two thread functions called senderFunct and receiverFunct. Each function has a local Message struct containing a Point3D struct. We create a global mqID variable to contain the ID assigned to our message queue. Since the ID is global and shared by both thread functions, we don't have to pass a parameter when creating our threads. code format="cpp" mqID = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); code

The sender thread sends the data in its message struct using a msgsnd function call, increments the coordinates by 1, and sleeps for a second. This is repeated in an infinite loop.

The receiver thread constantly checks the message queue with a msgrcv function call and then prints the x, y and z coordinates that are stored in its local message struct.

Since the threads are running a function that never returns, we have to terminate the application when testing. This means that the message queues remain in the system, and we have to manually delete them to clean up after ourselves. This is done by navigating to the ~/proc/sysvipc folder and finding the msqid's of the 'active' queues and then delete them using the ipcrm - q command.

Exercise 5.1.3-6
//Create a template class MsgWrapper. This class should have only two member variables: type of type// //long int and data of type Msg. Both members should be public, and type must be the first field.//

Template messageWrapper class code format="cpp" template class MsgWrapper { public: long int type; Msg data; }; code

//Create the template function sendMsg:// code format="cpp" template ssize_t sendMsg(int msgQId, const Msg& data) {   MsgWrapper msg; msg.data = data; msg.type = 1; return msgsnd(msgQId, (void *) &msg, sizeof(msg.data), 0); }

code

//Create the template function receiveMsg:// code format="cpp" template ssize_t receiveMsg(int msgQId, Msg& data) {   MsgWrapper msg; int result = msgrcv(msgQId, (void*) &msg, sizeof(msg.data), 0, 0); data = msg.data;

return result; } code

Using these template functions simplifies our program, since all we need to do is create a point object in the thread functions and then simply make use of the template wrapper functions to take care of the 'packing/unpacking' and sending/receiving of the data.

=LAB Exercise 5.2= //The following exercise was completed using our teachers handout files.//

Exercise 5.2.1
//Create a thread function airspeedHdl that waits for airspeed input in a message queue and outputs the// //received value to the console. Similarly, create a thread function headingHdl that waits for heading input// //and outputs it to the console.//

By using the template functions from exercise 5.1 we implemented a way for our handler functions to receive an object from a message queue and output either speed or heading(depending on the handler). Below you will see an example of our airspeed handler function, airspeedHdl.

code format="cpp" void * airspeedHdl(void * ) {   AirspeedMsg airmsg; while(1) {       receiveMsg(id3, airmsg); cout <<"\nSPD: Airspeed set to: " << airmsg.getSpeed << " knots." << endl; }

return NULL; } code

Exercise 5.2.2
//Create a thread function interpreter that waits for input in an input message queue, interprets whether it// //is airspeed or heading data, and forwards the data to the applicable handler in that handler’s message// //queue.//

Our interpreter has both a heading-, airspeed- and an input-Message object. It waits for input using our receiveMsg template function and interprets it. An object of either type airspeedMsg or headingMsg is then sent to the message queue after the value of either the heading or the airspeed has been set. Below you will see a snippet of the function only including the operations done for an "airspeed input" code format="cpp" void * interpreter(void * ) {   HeadingMsg headmsg; AirspeedMsg airmsg; InputMsg inmsg;

while(1) {       receiveMsg(id1, inmsg); if(inmsg.getInputType == 0 ) {           airmsg.setSpeed(inmsg.getInputValue); sendMsg(id3,airmsg); } code

Exercise 5.2.3
//Create a thread function inputHdl that prompts the user for input (heading or airspeed), validates the in-// //put and, if the input is valid, forwards the message type (heading or airspeed) and value it to the interpreter// //in a message queue.//

The function was implemented by using an inputMsg object that included both the type of input the user had chosen(Heading or Airspeed) and the value of said type. Both the type and value is appropriately validated and forwarded to the interpeters message queue who is then responsible for passing the information on. Below is shown a snippet of the code used for the implementation of the input handler.

code format="cpp" cout << "\nINP: What do you wish to set: (A)irspeed, (H)eading or (Q)uit?"; cin >> choice; if ( (choice == 'A' ) || (choice == 'a')) {           inmsg.setInputType(inmsg.AIRSPEED);

do           { cout << "\nINP: Enter Airspeed between 100 and 800 :"; cin >> value; }while(value < 100 || value > 800); code

Exercise 5.2.4
//“Glue” the system together by creating a program that creates the necessary message queues and starts the// //necessary threads. The program should clean up and terminate when the user presses ‘Q’. Test your sys-// //tem.//

We initialized the IDs of our message queues globally and assigned them in our main meaning we did not have to pass their values along as arguments in the creation of our threads.

The test of the system showed the following ouput: