讲解:EEEN30052、C/C++、C/C++、Concurrent SystemsR|C/C++

EEEN30052 Concurrent Systems 2018-19Assignment1. IntroductionThis assignment is concerned with simulating some aspects of a simple embedded computersystem. You may choose between two versions: A1 or A2. Each is worth a different percentageof the overall coursework mark: A1 is a simplified version of the assignment and is worth 50%,while A2 is the full version and is worth 100%.The diagram shown in Figure 1 is a model of a system that is responsible for gatheringenvironmental data from a set of three sensors, each of a different type. In the model a set ofthreads (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 ata time. Thus, in order to acquire data, each thread must gain sole access to the BC, configure it tosample from a specific sensor, and sample the data. In order to transmit the data, a thread mustgain access to one of two communications links via a Link Access Controller. Having gainedaccess, it sends its data, and then releases the link. Each thread may use either communicationslink, but once it has gained access to a particular link, no other thread should be allowed to usethat link until it is released.Figure 12If you choose to do A2 you should start by implementing A1, but you will not be required todemonstrate it or upload a copy (of A1). If you choose A1 you do not need to attempt A2, ordemonstrate/upload it. However, in both cases your program should print out messagesclearly indicating the identity of the calling thread and what action it is performing.2. A1 – worth 50% of total coursework marksWrite a C++ program that creates six threads where each thread is identified by an integer and has areference to an object of class BC, which is described below. Each thread executes the following sequence50 times: Request use of the BC by calling the requestBC() method of the BC object. This call attemptsto lock the BC to prevent access by other threads. The thread should print out its identity when thecall is successful. Select a sensor by generating a random number between 0 and 2 inclusive, where 0 represents thetemperature sensor, 1 represents the pressure sensor, and 2 represents the capacitive sensor. Usingthe number generated, request a sample value from the selected sensor by calling the BCsgetSensorValue()method. This returns a double value on the basis of the sensor that wasselected. The thread then obtains the sensor type by, for example, calling the BCsgetSensorType()method. Print out the sensor type and value obtained, together with the threads identity. Increment a counter each time a particular sensor is accessed (there is a different counter for eachsensor 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 booleanmember called lock to help ensure mutually exclusive access to the BC. Hence when a thread wishes toaccess the BC it calls requestBC(), which in turn checks the value of lock. If the BC is not currentlyin use (i.e. lock is false), the thread sets lock to true and the thread will be allowed to proceed to usethe BC. However, if the BC is in use, then the thread calling requestBC() should be suspended until theBC 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), whichare 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(), butmust implement getValue(), otherwise they are also designated abstract (abstract classes cant beinstantiated). Each sensor returns values randomly chosen from within the ranges shown in Table 1.Sensor Range of valuesTempSensor 10-30PressureSensor 95-105CapacitiveSensor 1-5 Table 13The main function instantiates the sensors (it is recommended to use a vector rather than an array for thispurpose), and creates six threads. It also creates one instance of class BC, passing the vector to it byreference. It should initiate execution of the threads and should not terminate until all threads haveterminated. To help you get started the following is a partially-complete skeleton of the program://comment: authors 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) //constructor : sensorType(type) {} //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 Sensorclass TempSensor : public Sensor { //syntax declares a derived class public: TempSensor (string& s) //constructor : Sensor(s) {} virtual double getValue() { //return a random value of ambient temperature between 10 and 30 .... } //end getValue}; //end class TempSensorcontinued..4class PressureSensor : public Sensor {........}; //end class PressureSensorclass CapacitiveSensor : public Sensor {........}; //end class CapacitiveSensorclass 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 lockedstd::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) {.... for (i=0; i // 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 sensors type: ....// increment counter for sensor chosen (to keep count of// how many times each was used)5continued..// release the BC: ....// delay for random period between 0.001s – 0.01s: .... }}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 //launch the threads: .... } //wait for the threads to finish: .... cout //print out the number of times each sensor was accessed: .... return 0;}The code is incomplete in a number of different senses, and you must modify it in order to complete A1.You are free to include any additional methods/functions/variables/constants, as you think necessary. Noteon commenting: a solution that is poorly commented will lose up to 5% of the total marks, and one thatdoes not calculate the delay period correctly will also lose up to 5%.Part of an example output is shown below:6Notes on the Program2.1 Thread IdentityObtaining the id value of a thread in C++11 is done withstd::this_thread::get_id()-however this returns an object not an integer, and although this can be passed to coutfor printing (e.g. cout simple way to cast it to an int.For example, if you create say, three threads, and printed out their ids, you might get234Ideally, we want to be able to associate a known integer id with each thread so we can identify them asthread 0, thread 1, etc..One solution is to create a std::map of thread ids v. integers, e.g.thread id int value 2 0 3 1 4 2..etc.To associate the thread id with an integer value in a map, the following might be helpful: std::mutex mu; //declare a mutex std::unique_lock map_locker(mu); //lock the map via the mutex. //insert the threadID and id into the map: threadIDs.insert(std::make_pair(std::this_thread::get_id(), id)); map_locker.unlock(); //were done, unlock the map.Such code need only be executed once, and could for example, be added to the run function that eachthread executes. 7A recommended way to search the map by thread id is to use an iterator, e.g.: std::map ::iterator it = threadIDs.find(std::this_thread::get_id()); if (it == threadIDs.end()) return -1; //thread id NOT found else return it->second; //thread id found, return the //associated integer –note the syntax.It might be useful to put the search code in a separate function.You will need the following preprocessor directive in order to use a map: #include For more info about maps, with more examples, see for example:http://thispointer.com/stdmap-tutorial-part-1-usage-detail-with-examples/2.2 Creating a delay by generating random values.One way to generate say, random integers, is to use a pseudo-random number generator (prng), and seedit with a value. The code below shows one way of doing this (adapted fromhttp://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution)std::mt19937 gen(time(0)); //A prng seeded by time(0). //time(0) gives the number of seconds elapsed since the start//of the world according to Unix (00:00:00 on 1st January 1970).std::uniform_int_distribution dis(1, 1000); //set up the distribution //from which integers will be drawn.int n = dis(gen); //generate a pseudo-random integer between 1-1000.-the pseudo-random number is stored in n.You will need the following preprocessor directives in order to use the above example code:#include #include Note that only a single generator is necessary, which only needs to be initialised once. Furthermore, asolution that does not calculate the delay period correctly will lose up to 5% of the total marks.2.3 Vectors or Arrays?A vector and an array are similar in that they both contain a list of data, however the basic difference isthat the size of an array is fixed, whereas a vector grows automatically as more items are added to it.Further代写EEEN30052作业、代写C/C++语言作业、C/C++程序作业代做、代做Concurrent Systems作业more, the availability of methods associated with vectors make them very flexible.In general in C++11 it is straightforward to create arrays of objects of classes from the standard library,such as std::thread, for example. However, arrays of objects of user-defined classes, such asSensor, or Link, are more awkward to use. For such user-defined classes you may findstd::vector much easier to handle, for example:std::vector sensors; //vector of pointers to Sensor objectsor std::vector commsLinks; //vector of Link objectsA example tutorial is:http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4027/C-Tutorial-A-Beginners-Guide-tostdvector-Part-1.htm82.4 InheritanceIn C++ one class (the base class) can define methods and variables/constants (i.e. class members) whichcan be inherited by another (derived class). In principle this means that such methods/variables/constantsneed to be defined only once (thereby promoting re-useability) yet can be used by instances of both baseand derived classes. In the following example, B declares its own members, in addition to those inheritedfrom A:#include using namespace std;class A{ //base class public: A (int i) //constructor : x(i) { } //initialise private instance variable x void set_x (int a) { x = a; } //set value of x int get_x ( ) { return x; } private: int x; //instance variable}; //end class Aclass B : public A { //derived class public: B (int i, int j) //constructor must call As constructor : A(i) {p = j;} //initialise private instance variable p void set_p(int a) { p = a; } //set value of p int get_p( ) { return p; } private: int p; //instance variable}; //end class B//The following illustrates use:int main() { A a(3); //create instance of A, initialise member variable//x to 3 a.set_x(4); //change x to new valuecout B b(5,4); //create instance of B and initialise member //variables x to 5 and p to 4 b.set_x(6);//use b uses inherited method to set new value of xcout cout }prints out464If a class contains one or more methods that are declared virtual then the class is said to be abstract andcant be instantiated; however any derived classes from which instances are required are then obliged todefine the method. This is useful if, for some reason it didnt make sense to define the method in the baseclass, yet you still wanted derived classes to have it, but define it in different ways. Using the above as anexample, if in class A we had declared set_x() as a virtual method, i.e. virtual void set_x (int a) = 0;//syntax specifies method as virtualthen any attempt to instantiate A now fails:9 A a(3); //FAILS –cant make an instance of abstract class ABecause B doesnt implement set_x() the following also fails to compile: B b(5,4); //FAILS –cant make an instance of BIn order for this statement to compile, B must implement set_x(), for example by writing void set_x (int a) { x = a; } //set value of xInheritance is a feature of object-oriented software design that permits the use of powerful techniques,such as polymorphism. The following link provides more information:http://www.cplusplus.com/doc/tutorial/inheritance/3. A2 – worth 100% of total coursework marksIn A1 we were concerned with creating threads and being able to lock access to the Bus Controller. In thisversion we extend the solution to include access to the communications links. In particular, the threadsshould request a Link from a LinkAccessController object. When one is available, the samplevalues that the thread has acquired can be transmitted. The Link object is used to copy this data to theReceiver object. To facilitate this, each thread stores sensor data in objects of a class calledSensorData, which stores the samples internally in a vector.The main program should create and initiate all the threads, and should wait until they have all haveterminated before calling the Receiver’s method that prints out all the sensor data.Part A2 builds on A1 and requires the following additional classes:SensorData. As indicated above, data sampled by each thread is stored in a vector managed byinstances of this class. Once started, each thread would create three instances, one for each sensor type.When a sample is received from the Bus Controller its type is checked, and then stored in the appropriateSensorData object. Later, when the time comes to transmit the data, these objects are sent to theReceiver via a link. The partial code for SensorData is given below:class SensorData { //Utility class to store sensor data public: SensorData(string type) //Constructor : sensor_type(type) {} string getSensorType() {return sensor_type;} std::vector getSensorData() {return sensor_data;} void addData(double newData) {....} private: .... std::vector sensor_data;}; //end class SensorDataLinkAccessController. As indicated above, there are two communications links that can beaccessed simultaneously. The actual number is defined by a global constant:int const NUM_OF_LINKS = 2; 10A single instance of the LinkAccessController class, called lac, controls access to these links,ensuring that they can be used simultaneously. However, if all the links are in use and additional threadsattempt to gain access to one, these latter threads should be suspended until one or more links becomeavailable. Threads should print out their identity, together with their actions, when accessing links: i.e.when they successfully acquire and release a link, and when (if) they are suspended. The partial code forLinkAccessController is given below.class LinkAccessController { public: LinkAccessController(Receiver& r) //Constructor : myReceiver(r), numOfAvailableLinks(NUM_OF_LINKS) { for (int i = 0; i commsLinks.push_back(Link(myReceiver, i)); } } //Request a comms link: returns a reference to an available Link. //If none are available, the calling thread is suspended. Link& requestLink() { .... return std::ref(commsLinks[linkNum]); } //Release a comms link: void releaseLink(Link& releasedLink) { .... } private: Receiver& myReceiver; //Receiver reference int numOfAvailableLinks; std::vector commsLinks; std::mutex LAC_mu; //mutex....}; //end class LinkAccessControllerLink. Instances of this class represent the communication links in the system. The partial code for Linkclass is given below:class Link { public: Link (Receiver& r, int linkNum) //Constructor : inUse(false), myReceiver(r), linkId(linkNum) {} //check if the link is currently in use bool isInUse() { return inUse; } //set the link status to busy void setInUse() { inUse = true; } continued..11 //set the link status to idle void setIdle() { inUse = false; } //write data to the receiver void writeToDataLink(SensorData sd) { ....} //returns the link Id int getLinkId() { return linkId; } private: bool inUse; Receiver& myReceiver; //Receiver reference int linkId;}; //end class LinkReceiver. An instance of this class called theReceiver receives the sensor data from the Linkobjects via calls to a method called receiveData(), which in turn determines the sensor type andwrites it into the appropriate vector (there is one vector of type double for each sensor type). The partialcode for class Receiver is given below.class Receiver { public: Receiver () { } //constructor //Receives a SensorData object: void receiveData(SensorData sd) { .... } // print out all data for each sensor: void printSensorData () { ....} private://mutex:.... //vectors to store sensor numeric data received from threads:std::vector temp_data;....}; //end class Receiverrun function.The run function for each thread should be extended. The following steps should be added to thesequence given in version A1:For each sensor type request access to a link; the thread should print out its identity and transmit the data for that sensor type to the Receiver; release the link, printing out its identity once more; once a link has been released, delay for a random time between 1 and 10 milliseconds.12A link can be conveniently obtained using a pointer as follows:Link* link = &lac.requestLink();and used to send data to the Receiver with: link-> writeToDataLink(...); //note pointer syntaxA link can be released with: lac.releaseLink(*link);main function.The main function creates the following objects/data structures: theBC, sensors and the_threads-as developed in part A1 of this assignment. lac-an object of class LinkAccessController. theReceiver-an object of class Receiver.int main() { //declare and initialise a vector of pointers to Sensors:std::vector sensors;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 the Receiver: .... // Instantiate the LinkAccessController: .... //instantiate and start the threads: std::thread the_threads[MAX_NUM_OF_THREADS]; //array of threads for (int i = 0; i //launch the threads: .... } //wait for the threads to finish: .... // Print out all the data in the Receiver: .... cout return 0;}Notes on the ProgramAs per A1, a solution that is poorly commented will lose up to 5% of the total marks, and one that doesnot calculate the delay period correctly will also lose up to 5%. You are also expected to use the globalconstants defined in the program in a consistent way throughout.134. Laboratory ArrangementsYour solution to the assignment (A1 or A2) will be demonstrated in Barnes Wallis on your final allocatedlab for Concurrent Systems (please check your timetable for the actual date). Demonstration of yourprogram at other times is not permitted. You will be expected to upload a copy of the program toBlackboard for marking during the demonstration.NOTE CAREFULLY: a learning objective of this assignment is to be able toexplain how a concurrent program works. During the demonstration you willbe asked simple questions about your program, for example the effect on theprogram of changing one or more of the constants or variables. Marks will bededucted if you cannot answer the questions that you are asked.5. DeliverablesAn electronic copy of your program should be uploaded at the end of the final session. Programs withoutcomments or with few comments will automatically receive low marks.6. PlagiarismThis is an individual assignment. Any plagiarism will be referred to the Director of Studies and penaltieswill be applied in accordance with University policy.转自:http://ass.3daixie.com/2018111154047171.html

你可能感兴趣的:(讲解:EEEN30052、C/C++、C/C++、Concurrent SystemsR|C/C++)