I3ISU_Opgave8

=Exercise 1 Creating a message queue= code format="cpp" typedef struct : public Message {   int x;    int y;    int z; } Point3D;
 * MsgQueue.h**

class MsgQueue { public:

enum {   POINT3D = 1 };

typedef struct {   unsigned long ID; Message* msg; } msgStruct; // Defined a struct for message

MsgQueue(int maxSize); ~MsgQueue; void send(unsigned long id, Message* msg = NULL); Message* receive(unsigned long id); void handler(Message* msg, unsigned long id); code In this file we define a struct to point3D with the function we want to send. We also define an enum that contains the communacating ID for this exercise. The last struct is used in our message queue and contains the message and the messages ID.

STL container: We have chosen to use queue because it fullfills our need for first in, first out functionality.

code format="cpp" void MsgQueue::send(unsigned long id, Message* msg) {   pthread_mutex_lock(&mutex_);
 * MsgQueue.cpp**

while(currentSize_ > maxSize_) pthread_cond_wait(&spaceInQueue_, &mutex_);

msgStruct tmpStruct;

tmpStruct.ID = id; tmpStruct.msg = msg;

msgQueue_.push(tmpStruct);

currentSize_++;

pthread_cond_signal(&entityInQueue_);

pthread_mutex_unlock(&mutex_);

}

Message* MsgQueue::receive(unsigned long &id) {   msgStruct tmpStruct;

pthread_mutex_lock(&mutex_);

while(currentSize_ < 1) pthread_cond_wait(&entityInQueue_, &mutex_); // Wait for entity to enter queue

tmpStruct = msgQueue_.front; // Fetch first entity msgQueue_.pop; // Removes front entity from queue currentSize_--;

pthread_cond_signal(&spaceInQueue_); pthread_mutex_unlock(&mutex_);

id = tmpStruct.ID; return tmpStruct.msg; } code

In this file we implement the send and recieve functions. In the send function we test for space in the queue and if there is no space the function waits for free space. We then declare a temporary struct that contains message and an ID and is pushed to the queue. A signal is then transmitted to threads waiting for new entities.

The Receive function gets an referance to an unsigned long as ID, and return a pointer to the message. The functions checks if there is any messages avaible, if none it waits. When there is a message, the id is returned via the ID parameter and the message is returned normally.

This file contains a virtual destructor that makes it possible to use polymorfi to send the messages with message as the base class.
 * message.h**

=Exercise 2 Sending data from one thread to another= main.cpp code format="cpp" void* sender(void*) {   for(int i = 0; i < 5; i++) {       Point3D* tmpPoint3D = new Point3D; tmpPoint3D->x = i;       tmpPoint3D->y = i;        tmpPoint3D->z = i;

msgQueue.send(msgQueue.POINT3D, tmpPoint3D); sleep(1); }

pthread_exit(NULL); }

void* reciver(void*) {   for(int i = 0; i < 5; i++) {   unsigned long ID; Message *tmpMessage;

tmpMessage = msgQueue.receive(ID);

msgQueue.handler(tmpMessage, ID); }

pthread_exit(NULL); }

code sender makes the message and sends it. Receiver receives the message and sends it to the handler: code format="cpp" void MsgQueue::handler(Message* msg, unsigned long id) {   switch(id) {   case POINT3D: Point3D *P3DM; P3DM = dynamic_cast(msg); cout << "X: " << P3DM->x << endl; cout << "Y: " << P3DM->y << endl; cout << "Z: " << P3DM->z << endl << endl;

delete P3DM;

break;

default: cout << "Unknown State" << endl; break; } } code The handler is in MsgQueue.cpp. This function takes the message and the ID. Runs a switch/case on the ID and then handles the message accordingly.

In our program the receiver disposes the message. When it is done with the message it throws it away. If it was a scenario with multiple producers and one consumer, it would also be the consumer that deletes the elements because otherwise the producers could accidentaly delete each others elements. Provided that the producers sends with the same ID's. ID is not for finding different producers but for finding different messages. It should be the consumer. Because it is the consumer that gets the tasks and therefore the consumer should keep control of the tasks. We do it by declaring them globbaly. Another way to do it is by declaring them in main and then send them with pointers in the thread arguments.
 * Questions to consider:**
 * **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** Yes. We do it with inheritance.
 * **By composition or association** No.

Link to code files for exercise 1 and 2: Files = = =Exercise 3 Enhancing the PCLS with Message Queues= code format="cpp" class MsgQueue { public:
 * MsgQueue.h**

enum {   CLOSEGATE = 1, GATEOPEN = 2, OPENGATE = 3 }; code We have adapted our enum with the ID's necessary for this exercise.

code format="cpp" void MsgQueue::handler(Message* msg, unsigned long id) {	switch(id) {	case CLOSEGATE: cout << "Gate is closing" << endl; break;
 * MsgQueue.cpp**

case GATEOPEN: cout << "Gate is open" << endl; break;

case OPENGATE: cout << "Gate is opening" << endl; break;

default: cout << "Unknown State" << endl; break; }

delete msg; }

code Our handler contains a switch, and prints the message associated with the supplied ID.

code format="cpp" // MsgQueues MsgQueue entryQueue(5); MsgQueue exitQueue(5);
 * CarPark.cpp**

void* carController(void*) {	unsigned long mID; Message *message;

entryQueue.send(entryQueue.OPENGATE);

message = entryQueue.receive(mID); entryQueue.handler(message, mID);

entryQueue.send(entryQueue.CLOSEGATE);

sleep(5); // Waiting time for cars

exitQueue.send(exitQueue.OPENGATE);

message = exitQueue.receive(mID); exitQueue.handler(message, mID);

exitQueue.send(exitQueue.CLOSEGATE);

return 0; }

void* exitController(void*) {	unsigned long mID; Message *message; while(1) {		message = exitQueue.receive(mID); exitQueue.handler(message, mID);

exitQueue.send(exitQueue.GATEOPEN);

message = exitQueue.receive(mID); exitQueue.handler(message, mID); }

return 0; }

void* entryController(void*) {	unsigned long mID; Message *message; while(1) {		message = entryQueue.receive(mID); entryQueue.handler(message, mID);

entryQueue.send(entryQueue.GATEOPEN);

message = entryQueue.receive(mID); entryQueue.handler(message, mID); }

return 0; } code

We have implemented the message queue in our carpark program. So it now works with send and receive in the message queue, instead of with conditionals and mutex locks/unlocks. We have two message queues, one for entrance and one for exit. This is because they need to be able to handle the messages independently of eachother.

Link to files for exercise 3: Files.

Link to sequence diagram for exercise 3: [|Diagram.] Message* MsgQueue::receive(unsigned long &id){ msgStruct tmpStruct; pthread_mutex_lock(&mutex_); while(currentSize_ < 1) pthread_cond_wait(&entityInQueue_, &mutex_); //Wait for entity to enter queue// // tmpStruct = msgQueue_.front; // Fetch first entity msgQueue_.pop; // Removes front entity from queue currentSize_--; pthread_cond_signal(&spaceInQueue_); pthread_mutex_unlock(&mutex_) id = tmpStruct.ID; return tmpStruct.msg; }