Document Version Publisher Pdf
Total Page:16
File Type:pdf, Size:1020Kb
Kent Academic Repository Full text document (pdf) Citation for published version Brown, Neil C.C. and Welch, Peter H. (2003) An Introduction to the Kent C++CSP Library. In: Communicating Process Architectures 2003, SEP 07-10, 2003, UNIV Twente, Enschde, Nederlands. DOI Link to record in KAR http://kar.kent.ac.uk/13921/ Document Version Publisher pdf Copyright & reuse Content in the Kent Academic Repository is made available for research purposes. Unless otherwise stated all content is protected by copyright and in the absence of an open licence (eg Creative Commons), permissions for further reuse of content should be sought from the publisher, author or other copyright holder. Versions of research The version in the Kent Academic Repository may differ from the final published version. Users are advised to check http://kar.kent.ac.uk for the status of the paper. Users should always cite the published version of record. Enquiries For any further enquiries regarding the licence status of this document, please contact: [email protected] If you believe this document infringes copyright then please contact the KAR admin team with the take-down information provided at http://kar.kent.ac.uk/contact.html Communicating Process Architectures – 2003 139 Jan F. Broenink and Gerald H. Hilderink (Eds.) IOS Press, 2003 An Introduction to the Kent C++CSP Library Neil BROWN and Peter WELCH Computing Laboratory, University of Kent, Canterbury, Kent, CT2 7NF, England. [email protected], [email protected] Abstract. This paper reports on a CSP library for C++, developed over the past year at the University of Kent. It is based on the OO-design and API of JCSP and the lightweight algorithms of KRoC occam, with extensions to exploit specific C++ ca- pabilities (such as templates). Both user-level and operating system threads are used to provide a range of implementation options and semantics (e.g. for managing block- ing system calls intelligently) that run efficiently under either Windows or Linux. The library is presented from the user’s point of view, mainly by way of a tutorial. Im- plementation details are also outlined and some benchmark results given. The per- formance of C++CSP is between that of KRoC occam and JCSP — fairly close to KRoC. 1 Background This year sees the 25th anniversary of C.A.R. Hoare’s paper describing Communicating Se- quential Processes (CSP) [1, 2], a new programming model for dealing with parallelism and concurrency that has a strong mathematical basis. Supported by a range of direct implemen- tation technologies, CSP avoids most of the fundamental problems inherent in concurrent design – allowing it to be used with confidence by systems engineers with only a modest amount of training and no specialist mathematical knowledge. Despite this, no mainstream operating systems or programming languages have built- in support for CSP mechanisms. For concurrency, they offer only unstructured varieties of threads and optional locking mechanisms (such as semaphores or monitors). They provide no support to enforce correct and efficient use of those locks – and cannot be made to provide it. Received wisdom[3] is that this concurrency is hard, should only be used as a last resort (for performance reasons) and only by very experienced designers and programmers. That received wisdom is correct. But CSP turns this around. Of course, occam[4, 5] provides the standard for CSP implementation against which oth- ers must be measured – but occam is not (yet) a mainstream language. For C, CCSP[6] is a library and run-time kernel that provides the occam model. JCSP[7] and CTJ[8] are CSP/occam libraries for Java. This paper reports on C++CSP: a CSP library for C++ that combines an Object Oriented API (derived from JCSP, but with modifications to take advan- tage of specific C++ capabilities, such as templates) with fast kernel support (along the lines of CCSP and occam). C++CSP runs native under either Windows or Linux/Unix. Applications, therefore, have direct access to all standard Windows – or Linux/Unix – libraries. This paper provides a user’s introduction to the library, describes some of the internal workings and provides early performance figures. It assumes readers have familiarity with the basic ideas and mechanisms of CSP, occam, JCSP and C++. 140 N.C.C. Brown and P.H. Welch / An Introduction to the Kent C++CSP Library 2 Library Details At the heart of the CSP paradigm are processes and channels – processes being pieces of code that can be executed in sequence or in parallel and channels being the means by which they communicate. Like JCSP before it, C++CSP adopts an object-oriented approach to implementing CSP. A process is a subclass of CSProcess, and channels are classes, such as the standard one-to- one unbuffered channel One2OneChannel. Channels are templated classes (the mechanism for generic programming in C++) that can be used to communicate any assignable type, be it a primitive, a “pod” class or a more complex class. In a typical scenario, a parent process creates a channel and passes a reading end (also a class – Chanin) to one process and a writing end (again, a class – Chanout) to another process. That way, neither child process can access the channel directly to try and obtain a class representing the opposite end of the channel. As in JCSP, a new process is implemented by declaring a new class as a child of the CSProcess class and implementing the void run() method (though in C++CSP this is protected rather than public1). Unfortunately, it is necessary to pass to the constructor of CSProcess the size of the stack needed for the process. This will be explained later. The C++CSP library provides: • processes (run either in sequence or in parallel); • channels (either or both of the reading and writing ends may be shared; also, they may be buffered using a variety of library or user-defined buffers); • parallel channel communications (a special case of parallelism included for conve- nience); • ALTernatives; • buckets and barriers[9]; • mobile objects with the same semantics as their (modern) occam counterparts; • easy and secure channel poisoning for clean shutdown; • support for Microsoft Windows (98 and later); • support for Linux and most other Unix-variants. 3 Tutorial 3.1 The Semantics of Assignment and Communication Channel communication is just a distributed form of assignment – a value is computed in one process and assigned to a variable in another (after synchronising the two processes of course). In occam, there is the equivalence: FOO x, y: FOO x, y: ... ... x := y equals CHAN FOO c: PAR c!y c?x 1This means that processes can only be run by the library itself and cannot be run directly by the user, due to problems with stacks that will be explored later in section 4.2. N.C.C. Brown and P.H. Welch / An Introduction to the Kent C++CSP Library 141 Therefore, the semantics of communication must be compatible with the semantics of assignment. In C++, the meaning of the assignment operator, =, can be overridden to mean whatever the programmer wishes it to mean... and this will be reflected in the meaning of communica- tion in the C++CSP library. So, if a class overrides assignment to mean “shallow copying”, a shallow copy of an object will be sent across a C++CSP channel. If a class has not over- ridden its assignment operator, then a “member-wise” copy (the default for assignment of C++ objects) is received by the reading process. If the channel carries array types, only the pointers will be communicated, since in C++ an array is treated as a pointer. If the channel carries primitive types (int, float etc.), only their values will be communicated. In this paper, most of the examples work with int-carrying channels. If Bar is a class, then Bar-carrying channels are handled with equal ease - examples are referred to in Sections 5.3 and 6.3. 3.2 Our First Program We will now look at creating a simple program using the C++CSP library. There will be a writer process that writes 100 integers to a channel then exits, and a reader process that reads 100 integers from a channel and exits. These processes are declared as follows2: class Writer : public CSProcess { private: Chanout<int> out; //writing end of the channel protected: virtual void run(); //overrides the method in CSProcess public: Writer(const Chanout<int>& o); //constructor }; class Reader : public CSProcess { private: Chanin<int> in; //reading end of the channel protected: virtual void run(); //overrides the method in CSProcess public: Reader(const Chanin<int>& i); //constructor }; The constructors are as follows (we will use an arbitrarily-sized large stack): Writer::Writer(const Chanout<int>& o) : CSProcess(65536),out(o) { } Reader::Reader(const Chanin<int>& i) : CSProcess(65536),in(i) { } The above pieces of code are a general template for any process. Each process is a child of CSProcess and must implement the run method. They will have as class members 2In all sample code, it is assumed that the namespace of the library, csp, is in scope. 142 N.C.C. Brown and P.H. Welch / An Introduction to the Kent C++CSP Library any channel ends they require; these are passed to the class constructor. As can be seen above, channel ends can be assigned for ease of use. Following the object-oriented paradigm, channel ends are the same regardless of what type of channel (buffered, shared, or both) they are attached to, allowing any channel type to be used with any process (bar a few exceptions regarding ALTernatives and shared channels).