Concurrent Systems

Order Description

1 Concurrent Systems 1. Introduction The diagram shown in Figure 1 is a model of a system that is responsible for gathering environmental data from a set of three sensors, each of a different type. In the model a set of threads (initially six) are used to gather the data, and then transmit it to a Receiver. Access to the sensors is via a Bus Controller (BC), such that only one thread is granted access at a time. Thus, in order to acquire data, each thread must gain sole access to the BC, configure it to sample from a specific sensor, and sample the data. In order to transmit the data, a thread must gain access to one of two communications links via a Link Access Controller. Having gained access, it sends its data, and then releases the link. Each thread may use either communications link, but once it has gained access to a particular link, no other thread should be allowed to use that link until it is released. Figure 12 1 . Write a C++ program that creates six threads where each thread is identified by an integer and has a reference to an object of class BC, which is described below. Each thread executes the following sequence 50 times: • Request use of the BC by calling the requestBC() method of the BC object. This call attempts to lock the BC to prevent access by other threads. The thread should print out its identity when the call is successful. • Select a sensor by generating a random number between 0 and 2 inclusive, where 0 represents the temperature sensor, 1 represents the pressure sensor, and 2 represents the capacitive sensor. Using the number generated, request a sample value from the selected sensor by calling the BC's getSensorValue()method. This returns a double value on the basis of the sensor that was selected. The thread then obtains the sensor type by, for example, calling the BC's getSensorType()method. • Print out the sensor type and value obtained, together with the thread's identity. • Increment a counter each time a particular sensor is accessed (there is a different counter for each sensor type). • Call releaseBC() to enable other threads to use the BC, printing out its identity once more. • Delay for a random time between 1 and 10 milliseconds. A function called run() is used to implement the above. Objects of class BC have a private boolean member called lock to help ensure mutually exclusive access to the BC. Hence when a thread wishes to access the BC it calls requestBC(), which in turn checks the value of lock. If the BC is not currently in use (i.e. lock is false), the thread sets lock to true and the thread will be allowed to proceed to use the BC. However, if the BC is in use, then the thread calling requestBC() should be suspended until the BC has been relinquished by another thread calling releaseBC(), which in turn sets lock to false. Thus threads are suspended –and resumed- depending on the value of lock. Each sensor is represented by its own class (TempSensor, PressureSensor and CapacitiveSensor), which are derived from a base abstract class called Sensor. Sensor has one virtual method called getValue(), and one non-virtual method called getType(). Classes derived from Sensor inherit getType(), but must implement getValue(), otherwise they are also designated 'abstract' (abstract classes can't be instantiated). Each sensor returns values randomly chosen from within the ranges shown in Table 1.3 Sensor Range of values TempSensor 10-30 PressureSensor 95-105 CapacitiveSensor 1-5 Table 1 The main function instantiates the sensors (it is recommended to use a vector rather than an array for this purpose), and creates six threads. It also creates one instance of class BC, passing the vector to it by reference. It should initiate execution of the threads and should not terminate until all threads have terminated. To help you get started the following is a partiallycomplete 'skeleton' of the program: //comment: author's name, ID, and date. //pre-processor directives: #include #include .... using namespace std; //global constants: int const MAX_NUM_OF_THREADS = 6; .... //global variables: .... //function prototypes: (as required) .... class Sensor { //abstract base class that models a sensor public: Sensor(string& type) : sensorType(type) {} //constructor //Declare a virtual method to be overridden by derived classes: virtual double getValue() = 0; //Declare non-virtual method: string getType() { //returns the type of Sensor that this is: .... } //Declare any instance variable(s): .... }; //end abstract class Sensor continued..4 class TempSensor : public Sensor { //syntax declares a derived class public: TempSensor (string& s) : Sensor(s) {} //constructor virtual double getValue() { //return a random value of ambient temperature between 10 and 30 .... } //end getValue }; //end class TempSensor class PressureSensor : public Sensor { .... .... }; //end class PressureSensor class CapacitiveSensor : public Sensor { .... .... }; //end class CapacitiveSensor class BC { public: //constructor: initialises a vector of Sensor pointers that are //passed in by reference: BC(std::vector& sensors): theSensors(sensors) {} void requestBC() { .... } double getSensorValue(int selector) { return (*theSensors[selector]).getValue(); } string getSensorType(int selector) { .... } void releaseBC() { .... } private: bool lock = false; //'false' means that the BC is not locked std::vector& theSensors; //reference to vector of Sensor pointers std::mutex BC_mu; //mutex .... }; //end class BC //run function – executed by each thread: void run(BC& theBC, int idx) {5 .... for (i=0; i< NUM_OF_SAMPLES; i++) { // NUM_OF_SAMPLES = 50 (initially) // request use of the BC: .... // generate a random value between 0 and 2, and use it to // select a sensor and obtain a value and the sensor's type: .... // increment counter for sensor chosen (to keep count of // how many times each was used) // release the BC: .... // delay for random period between 0.001s – 0.01s: .... } // end of for } // end of run int main() { //declare a vector of Sensor pointers: std::vector sensors; //initialise each sensor and insert into the vector: string s = "temperature sensor"; sensors.push_back(new TempSensor(s)); //push_back is a vector method. .... // Instantiate the BC: BC theBC(std::ref(sensors)); //instantiate and start the threads: std::thread the_threads[MAX_NUM_OF_THREADS]; //array of threads for (int i = 0; i < MAX_NUM_OF_THREADS; i++) { //launch the threads: .... } //wait for the threads to finish: .... cout << "All threads terminated" << endl; //print out the number of times each sensor was accessed: .... return 0; } // end of main The code is incomplete in a number of different ways, and you must modify it to complete A1. You are free to include any additional member functions/variables/constants, as you think6 necessary. Note on commenting: a solution that is poorly commented will lose up to 5% of the total marks, and one that does not calculate the delay period correctly will also lose up to 5%. Part of an example output is shown below: