Øvelse+8+-+Thread+Communication

=Exercise 1 Creating a message queue= To have something tangible for the message queue to handle, we start out creating class Message. This class will from now on serve as the basis (parent) of all messages that are passed around in our system. In other words all other messages must inherit from this class. Remember that the destructor must be virtual. Why is this last bit very important? Explain! code format="cpp" /* We Use Message.h as a base class, So the MESSAGEQUEUE CLASS can inherrit from it. The destructer must be a virtual funktion, so its behavior can be overridden.
 * 1) include
 * 1) include

class Message { public: Message{} /*We dont need to make a constructor, because i dosent do anything*/ virtual ~Message{} } code code format="cpp" /* In the constructor in MsgQueue.cpp we want to set our maximum queue size, if the maximum queue size isent set at the user its is default SIZE = 80 (Look at MsgQueue.hpp). We also want to initlize the cond variable and the mutex variable, to leran how to do that see: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

MsgQueue::MsgQueue(unsigned int maxSize) {   SIZE = maxSize; //Set maximum queue pthread_cond_init(&cond, NULL); // Initlize cond variable pthread_mutex_init(&m, NULL); //Initlize mutex variable } code code format="cpp" /* In our send funktion, we want to send a id and a message, we must use mutexes because we work on shared memory. To store our message we use a type of container adaptor named queue , it is specifically designed to operate in a FIFO context (first-in first-out), where elements are inserted into one end of the container and extracted from the other. To learn how to use a queue, see: http://www.cplusplus.com/reference/stl/queue/ **IT IS IMPORTANT TO WAIT FOR SPACE IN THE QUEUE OTHERWISE IT WILL CASH!!**

void MsgQueue::send(unsigned int id, Message* msg) { //Make a object Item, to store the identifier which is to be send and the msg is the message to be passed Item obj; obj.id = id; obj.msg = msg;

//Lock the mutex, pthread_mutex_lock(&m);

//Wait for space while(msgQueue.size >= SIZE) {  pthread_cond_wait(&cond, &m); }

//Push item to the queue msgQueue.push(obj);

//Unlock mutex and signal

pthread_mutex_unlock(&m); pthread_cond_broadcast(&cond); } code code format="cpp" /* In our receive funktion, we want to receive a message from the shared queue. We must use mutexes because we work on shared memory, to get our message we use the funktion front, from the container adaptor. To learn how to use a queue, see: http://www.cplusplus.com/reference/stl/queue/ **IT IS IMPORTANT TO WAIT FOR A MESSAGE IN THE QUEUE OTHERWISE IT WILL CRASH!!**

Message* MsgQueue::receive(unsigned int& id) { //Lock the Mutex pthread_mutex_lock(&m);

//Wait for queue to have a message while(msgQueue.empty) { pthread_cond_wait(&cond, &m); }

//Get oldest Item from the queue Item obj = msgQueue.front;

//Remove old Item from queue msgQueue.pop;

//Unlock mutex and signal pthread_mutex_unlock(&m); pthread_cond_broadcast(&cond);

//return id and msg id = obj.id; return obj.msg; } code code format="cpp" /* In our destructor we want to clean up. We must destory our mutex and our cond variable. We dont need to destory our queue, it will destroy when the scrope end.

MsgQueue::~MsgQueue { pthread_mutex_destroy(&m); pthread_cond_destroy(&cond); } code =Exercise 2 Sending data from one thread to another= Create a C++ struct named Point3D that contains x, y and z values (all integers). Then create two thread functions, sender and receiver hence known as the sender thread and receiver thread. The sender thread should send a Point3D object to the receiver thread via a message queue every second or so. The receiver thread should continuously wait for new messages and, on reception, print the x, y, and z coordinates of the received Point3D object to the console.

Create a function main that creates a message queue and then spawns two threads running sender and receiver respectively that communicate via this message queue.

Test your system - does the receiver thread receive what the sender sends?

Questions to consider: Elaborate on your design choice. code format="cpp" /* We make a enum, so we can use it as our ID.
 * Who is supposed to be responsible for disposing of the incoming messages?
 * Who should be the owner of the object instance of class MsgQueue; Is it relevant in this particular scenario?
 * How are the threads brought to know about the object instance of MsgQueue?
 * How does the struct Point3D relate to class Message in your particular design?
 * By inheritance
 * By composition or association

enum { POINT_ID = 0, POINT_EXIT = 1 }; code code format="cpp" /* We want to send our point3D struct as a message, to do that we need to inherit from our Message class. If we want to set x, y and z, we use new to make a object and now we can use pointers to set x, y and z.

struct point3D : public Message { int x;  int y;  int z; }; code code format="cpp" /* In the sender funktion, we have our queue, first we need to convert it back to a messagequeue pointer, form void pointer. To do that we need reinterpret_cast, there allows us to convert any pointer into any other pointer type. To leran more about reinterpret_cast, see: http://msdn.microsoft.com/en-us/library/e0w9f63b%28v=vs.80%29.aspx. Next we can get our message and send it, when we send it, we use our enum and the message to be send. **IT CAN BE IMPORNTANT TO REMEMBER A LITTLE DELAY** At last we send the enum exit and a empty message. void* Sender(void* queue) { //Converts back to messagequeue pointer, from void pointer MsgQueue* msgQptr = reinterpret_cast(queue);

//Initialize random number generator srand( time(NULL) );

for (int i=0; i<=5; i++) {   point3D* p = new point3D; // Make a object p -> x = rand%100; // Get a random number from 0 to 100 p -> y = rand%100; p -> z = rand%100;

msgQptr -> send(POINT_ID, p); // Send the enum and the message

sleep(1); }

msgQptr -> send(POINT_EXIT, new Message); // Send the enum and the message } code code format="cpp" /* In the Receiver funktion, we want to get a message from the queue, frist we need to convert it, with reinterpret_cast. To leran more about reinterpret_cast, see: http://msdn.microsoft.com/en-us/library/e0w9f63b%28v=vs.80%29.aspx. Next we get the message and the id from the queue. **IT IS IMPORTANT TO DELETE OUR MESSAGE, AFTER THEN HAVE BEEN USED.** void* Receiver(void* queue) { unsigned int id; Message* msg;

//Converts back to messagequeue pointer, from void pointer MsgQueue *msgQptr = reinterpret_cast(queue);

while(1) {   //receive returns a message pointer and set the parameter. id will contian ID of message. msg = msgQptr -> receive(id);

if(id == POINT_ID) {     //Convert Message to a point3D pointer point3D *ptr = reinterpret_cast(msg); std::cout << ptr-> x << " " << ptr-> y << " " << ptr-> z << std::endl; }   else {     std::cout << "EXIT_ID was called" << std::endl; break; }   delete msg; } delete msg; } code code format="cpp" /* In our main we first need to made a MsgQueue*, it will be the shared queue. **IT IS IMPORTANT AT THE SIZE ISENT 0** Then we spawn to threads and join them int main { MsgQueue* queue = new MsgQueue (1);

pthread_t thread0, thread1;

pthread_create(&thread0, NULL, Sender, (void*)queue); pthread_create(&thread1, NULL, Receiver, (void*)queue);

pthread_join(thread0, NULL); pthread_join(thread1, NULL);

return 0; } code =Exercise 3 Enhancing the PCLS with Message Queues= Reimplement your PCLS solution using Message Queues and thus messages as a means to communicate between car thread and door controller thread.

HINT: In each thread consider using a simple state machine, that controls the communication between the threads. This is especially bene cial due to the asynchronous nature of the system.

How do you handle state machines?

//We implement a enum, so we can use MsgQueue and state machine to implement the ParkALot system. The enum i shown under:// code format="cpp" enum {   ID_Car_Entry_Open_Req = 0, ID_Car_Entry_Open_Con = 1, ID_Car_Exit_Open_Req = 2, ID_Car_Exit_Open_Con = 3, ID_Car_Waiting_Enter = 4, ID_Car_Waiting_Exit = 5, ID_DONE = 6 }; code

// The entry and exit states come from requesting in our car thread: // code format="cpp" // create request to exit exitOpenRequest* ereq = new exitOpenRequest; ereq->mq_ = mq; // send request exitMq.send(ID_Car_Exit_Open_Req, ereq); code

// When we do this the request is processed in our entry function. The entry function receives the message and sends it to our handler: // code format="cpp" Message* msg = mq->receive(id); garageDoorOpenControllerHandler(msg, id); code

// Our handler process the message and respond it. // code std::cout << "Entry Request Recieved" << std::endl; entryOpenRequest* req = reinterpret_cast(msg); // create responds entryOpenConfirm* cfm = new entryOpenConfirm; cfm->result_ = true;

req->mq_->send(ID_Car_Entry_Open_Con, cfm); code

// This is received in our car thread and the state is changed. When the car is inside the PLCS it wants to leave again. This is handled the same way as entry. We create a thread for every car and for our entry and exit. Each gets a message queue. //

code format="cpp" /*All the code to ParkALot2012, there isen't any comments*/


 * 1) include "MsgQueue.hpp"
 * 2) include 
 * 3) include
 * 4) include

MsgQueue entryMq(10); MsgQueue exitMq(10); MsgQueue carMq(10);

enum {   ID_Car_Entry_Open_Req = 0, ID_Car_Entry_Open_Con = 1, ID_Car_Exit_Open_Req = 2, ID_Car_Exit_Open_Con = 3, ID_Car_Waiting_Enter = 4, ID_Car_Waiting_Exit = 5, ID_DONE = 6 };

int carWait = 0;

struct entryOpenRequest : public Message {   MsgQueue* mq_; };

struct entryOpenConfirm : public Message {   bool result_; };

struct exitOpenRequest : public Message {   MsgQueue* mq_; };

struct exitOpenConfirm : public Message {   bool result_; };

void garageDoorOpenControllerHandler(Message* msg, size_t id) {   switch(id) {   case ID_Car_Entry_Open_Req: {       std::cout << "Entry Request Recieved" << std::endl; entryOpenRequest* req = reinterpret_cast(msg); // create responds entryOpenConfirm* cfm = new entryOpenConfirm; cfm->result_ = true;

req->mq_->send(ID_Car_Entry_Open_Con, cfm);

break;} default: std::cout << "Unknown identifier" << std::endl; } }

void garageDoorExitControllerHandler(Message* msg, size_t id) {   switch(id) {   case ID_Car_Exit_Open_Req: {       std::cout << "Exit Request Recieved" << std::endl; exitOpenRequest* ereq = reinterpret_cast(msg); exitOpenConfirm* cfm = new exitOpenConfirm; cfm->result_ = true;

ereq->mq_->send(ID_Car_Exit_Open_Con, cfm); break;} default: std::cout << "Unknown identifier" << std::endl; } }

void* carDriver(void *data) {   int state = ID_Car_Waiting_Enter; unsigned int id = 0; MsgQueue* mq = static_cast (data);

for {       switch(state) {         case ID_Car_Waiting_Enter: {           // create request to enter entryOpenRequest* req = new entryOpenRequest; req->mq_ = mq; // send request entryMq.send(ID_Car_Entry_Open_Req, req); sleep(1);

//recieve answer Message* msg = mq->receive(id); entryOpenConfirm* cfm = reinterpret_cast(msg); if(cfm->result_) {               carWait++; std::cout << "Car driving into lot, there is now " << carWait << " car(s)" << std::endl; // drive into parking lot; srand(time(NULL)); sleep(rand%10); // set state state = ID_Car_Waiting_Exit; }           break;} case ID_Car_Waiting_Exit: {           // create request to exit exitOpenRequest* ereq = new exitOpenRequest; ereq->mq_ = mq; // send request exitMq.send(ID_Car_Exit_Open_Req, ereq);

//recieve answer Message* msg = mq->receive(id); exitOpenConfirm* cfm = reinterpret_cast(msg); if(cfm->result_) {                 carWait--; std::cout << "Car driving out of lot, there is now " << carWait << " car(s)" << std::endl; // drive out of parking lot; state = ID_DONE; }           break;} case ID_DONE: {           break;

}       }    } }

void* entryFunc(void *data) {   MsgQueue* mq = static_cast (data);

for {       unsigned int id; Message* msg = mq->receive(id); garageDoorOpenControllerHandler(msg, id); delete msg; } }

void* exitFunc(void *data) {   MsgQueue* mq = static_cast (data);

for {       unsigned int id; Message* msg = mq->receive(id); garageDoorExitControllerHandler(msg, id); delete msg; } }

int main(int argc, char* arg[]) {   int car = 3; char input;

pthread_t entryControllerThread, exitControllerThread, carThread[car];

pthread_create(&entryControllerThread, NULL, entryFunc, &entryMq); pthread_create(&exitControllerThread, NULL, exitFunc, &exitMq);

sleep(1);

for( int i = 0; i < car; i++ ) {       pthread_create(&carThread[i], NULL, carDriver, &carMq); sleep(1); }

while(1) {     std::cin >> input;

if(input == 'q' || input == 'Q') {       exit(1); }   } }

code