// ************************************************************** // * * // * Spheres -- Ping.cpp * // * * // * (C) Christian Scheideler, 2003 * // * * // ************************************************************** // Ping.cpp simply generates a list of 10 nodes that continuously // send a PING message to the neighbor // Special definitions and operations provided by Spheres.h: // // - Sphere: class that enables non-blocking method invocations (NMI). // To ensure the correct execution of NMIs, every method in a class // derived from Sphere that is to be called by NMI has to have the form // // void MethodName(usertype *plist) // // where plist is a pointer to any kind of usertype. // // - void Send(SpherePtr, SphereObj::Method, ParList): // This requests to call the method SphereObj::Method in the user object // referenced by SpherePtr using the parameter list referenced by ParList. // // - void Simulate(Time): // This runs a simulation for Time many rounds. // The Spheres.h class provides an environment for the simulation of // concurrent data structures, where concurrent executions are done at the // level of method invocations (i.e. each method invocation completes before // another method is invoked). To avoid inconsistencies in the data structure, // some general rules have to be obeyed: // // - A method may not have any side-effects other than modifying the // data inside the object. // // - A method must be total, meaning that it is well-defined for // EVERY legal state of the object. #include #include #include "Spheres.h" // parameter list for Node::Ping method class PingPList { public: int time; PingPList(int t) { time = t; } }; // parameter list for Node::Ack method class AckPList { public: int ID; int time; AckPList(int i, int t) { ID = i; time = t; } }; class Node: public Sphere { private: // own ID int ID; // pointers to left and right neighbor Node *left; Node *right; public: Node(int i) { ID = i; // set own ID }; void Connect(Node *l, Node *r) { // later, connections should be established via NMIs, but here // we just do it directly left = l; right = r; } void Ping(PingPList *p) { cout << ID << " sends PING #" << p->time << " to " << ID-1 << " and " << ID+1 << "\n"; // create two parameter lists for Node::Ack calls AckPList *pl1 = new AckPList(ID, p->time); AckPList *pl2 = new AckPList(ID, p->time); // invoke Node::Ack in left and right neighbor if (left!=NULL) Send(left, Node::Ack, pl1); if (right!=NULL) Send(right, Node::Ack, pl2); // call Node::Ping by itself to ensure periodic checks p->time++; Send(this, Node::Ping, p); // p is reused here and therefore not deleted like in Node::Ack } void Ack(AckPList *p) { cout << ID << " received PING #" << p->time << " from " << p->ID << "\n"; // deallocate space for p delete(p); } }; void main() { int i; PingPList *p; // generate array of node objects Node *List[10]; for (i=0; i<10; i++) List[i] = new Node(i); // connect node objects to a doubly linked list List[0]->Connect(NULL, List[1]); for (i=1; i<9; i++) List[i]->Connect(List[i-1], List[i+1]); List[9]->Connect(List[8], NULL); // generate requests to call Node::Ping in every node of the list for (i=0; i<10; i++) { p = new PingPList(1); Send(List[i], Node::Ping, p); } // run the simulation for 10 rounds Simulate(10); }