Basic services are targeted to non-specialized users wanting an easy manner of sending and receiving information through the network. Consequently, these services will have clear semantics as well as an easy interface. Since there are a large variety of basic classes in the standard C++, we will overload the input/output methods for each of such basic classes. See the example below:
class NetStream { public: NetStream (); // Default constructor // Constructor with source integer left unchanged NetStream (int, char **); // Init the communications ~NetStream (); // Default destructor void init(int,char**); // Init the communication system. Invoke it only ONCE void finalize(void); // Shutdown the communication system. Invoke it ONCE // BASIC INPUT SERVICES <comments> BASIC OUTPUT SERVICES // ============================================================================================================ NetStream& operator>> (bool& d); NetStream& operator<< (bool d); NetStream& operator>> (char& d); NetStream& operator<< (char d); NetStream& operator>> (short& d); NetStream& operator<< (short d); NetStream& operator>> (int& d); NetStream& operator<< (int d); NetStream& operator>> (long& d); NetStream& operator<< (long d); NetStream& operator>> (float& d); NetStream& operator<< (float d); NetStream& operator>> (double& d); NetStream& operator<< (double d); NetStream& operator>> (char* d); /*NULL terminated*/ NetStream& operator<< (char* d); NetStream& operator>> (void* d); /*NULL terminated*/ NetStream& operator<< (void* d); #ifdef _LEDA_ NetStream& operator>> (string& d); NetStream& operator<< (const string& d); template <class T> NetStream& operator>> (array<T>& d); template <class T> NetStream& operator<< (const array<T>& d); template <class T> NetStream& operator>> (slist<T>& d); template <class T> NetStream& operator<< (const slist<T>& d); template <class T> NetStream& operator>> (list<T>& d); template <class T> NetStream& operator<< (const list<T>& d); #endif int pnumber(void); // Returns the number of processes NetStream& _my_pid(int* pid); // Returns the process ID of the calling process NetStream& _wait(const int stream_type);// Wait for an incoming message in the specified stream NetStream& _set_target(const int p); // Stablish "p" as the default receiver NetStream& _get_target(int* p); // Get into "p" the default receiver NetStream& _set_source(const int p); // Stablish "p" as the default transmitter NetStream& _get_source(int* p); // Get into "p" the default transmitter ... };
Let us now describe the basic interface. First, the user must
include the netstream.hh
file in its program file. Then,
he or she must declare a NetStream
object. The constructor
may have no arguments or else it might have the two arguments of
the main" program or the \verb"init
method.
The user is supposed to make a init()
call before all the
system begin to work and a call to finalize()
for shutting down the
communication system (only once). New versions of NetStream will define
these methods as static
, thus allowing a class scope invokation
NetStream::init()
. In the middle of this parenthesis-like structure the
user can input/output basic data types from/to the NetStream
previously
declared object. Normal classes such as int", \verb"double
, and
char
are of course included among the large set of classes that can be
exchanged through the net.
#include "netstream.hh" int main (int argc, char** argv) { NetStream netstream; int mypid; ... netstream.init(argc,argv); // Initialize the comm system netstream << set_target(1) // Set the target process << set_source(1) // Set the source process << my_pid(&mypid);// Get the pid of the calling process ... netstream << 9 << 'a' << "hello world"; // Send data through the net netstream >> i >> c >> str; // Receive data from the net ... netstream.finalize(); // Shutdown the comm system } // main
As you notice, before engaging in input/output operations the user can
set/get the process number in the other end from/to which the
communication is being achieved. For this purpose, four methods
are readily provided (see NetStream
public interface). Notice that these,
as well as other methods, begin with an underscore character "_".
The reason is that the same methods exist for invocation inside
and inserter <<" or extractor \verb">>
operator in a single sentence. This is
included for compatibility with the manipulator philosophy
of standard streams in C++. A manipulator is a method that can be
fed into a >>" or \verb"<<
operator in order to perform a task. A
manipulator can be merged with standard input/output operations,
thus providing a nice and uniform interface for streams.
Manipulators can also have arguments; they look like normal
methods with the exception that they can be used in isertions and
extractions of a stream.
The method pnumber()
allows the user to know the number
of processes running in parallel, and the method _my_pid()
returns as an argument the process identifier of the calling
process in the set of parallel processes.
The method wait()
allows the user to wait for an
incoming message in a given stream. The most usual net stream the
user will need is the regular
stream for sending/receiving
normal data to/from other processes.
netstream << wait(regular); // Wait for a regular message
Finally, for these users having code that includes data types
from the LEDA library, next versions of the NetStream
class were
initially thought to support exchanging LEDA types such as string
,
array", \verb"slist", and \verb"list
. However, at present, some changes
in the availability of this data library and in the priorities of our project
have leaded to not supporting LEDA in NetStream
.
After the user has typed is parallel program by using
NetStream
, he or she can compile it with the usual
mpicc
operating system command and the run it with the
usual mpirun
command.