1 // Copyright (C) 2005, 2006 Douglas Gregor <doug.gregor -at- gmail.com>.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 /** @file communicator.hpp
8  *
9  *  This header defines the @c communicator class, which is the basis
10  *  of all communication within Boost.MPI, and provides point-to-point
11  *  communication operations.
12  */
13 #ifndef BOOST_MPI_COMMUNICATOR_HPP
14 #define BOOST_MPI_COMMUNICATOR_HPP
15 
16 #include <boost/assert.hpp>
17 #include <boost/mpi/config.hpp>
18 #include <boost/mpi/exception.hpp>
19 #include <boost/optional.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/mpi/datatype.hpp>
22 #include <boost/mpi/nonblocking.hpp>
23 #include <utility>
24 #include <iterator>
25 #include <stdexcept> // for std::range_error
26 
27 // For (de-)serializing sends and receives
28 #include <boost/mpi/packed_oarchive.hpp>
29 #include <boost/mpi/packed_iarchive.hpp>
30 
31 // For (de-)serializing skeletons and content
32 #include <boost/mpi/skeleton_and_content_fwd.hpp>
33 
34 // For (de-)serializing arrays
35 #include <boost/serialization/array.hpp>
36 
37 #include <boost/mpi/detail/point_to_point.hpp>
38 #include <boost/mpi/status.hpp>
39 #include <boost/mpi/request.hpp>
40 
41 #ifdef BOOST_MSVC
42 #  pragma warning(push)
43 #  pragma warning(disable : 4800) // forcing to bool 'true' or 'false'
44 #endif
45 
46 namespace boost { namespace mpi {
47 
48 /**
49  * @brief A constant representing "any process."
50  *
51  * This constant may be used for the @c source parameter of @c receive
52  * operations to indicate that a message may be received from any
53  * source.
54  */
55 const int any_source = MPI_ANY_SOURCE;
56 
57 /**
58  * @brief A constant representing "any tag."
59  *
60  * This constant may be used for the @c tag parameter of @c receive
61  * operations to indicate that a @c send with any tag will be matched
62  * by the receive.
63  */
64 const int any_tag = MPI_ANY_TAG;
65 
66 /**
67  * @brief Enumeration used to describe how to adopt a C @c MPI_Comm into
68  * a Boost.MPI communicator.
69  *
70  * The values for this enumeration determine how a Boost.MPI
71  * communicator will behave when constructed with an MPI
72  * communicator. The options are:
73  *
74  *   - @c comm_duplicate: Duplicate the MPI_Comm communicator to
75  *   create a new communicator (e.g., with MPI_Comm_dup). This new
76  *   MPI_Comm communicator will be automatically freed when the
77  *   Boost.MPI communicator (and all copies of it) is destroyed.
78  *
79  *   - @c comm_take_ownership: Take ownership of the communicator. It
80  *   will be freed automatically when all of the Boost.MPI
81  *   communicators go out of scope. This option must not be used with
82  *   MPI_COMM_WORLD.
83  *
84  *   - @c comm_attach: The Boost.MPI communicator will reference the
85  *   existing MPI communicator but will not free it when the Boost.MPI
86  *   communicator goes out of scope. This option should only be used
87  *   when the communicator is managed by the user or MPI library
88  *   (e.g., MPI_COMM_WORLD).
89  */
90 enum comm_create_kind { comm_duplicate, comm_take_ownership, comm_attach };
91 
92 /**
93  * INTERNAL ONLY
94  *
95  * Forward declaration of @c group needed for the @c group
96  * constructor and accessor.
97  */
98 class group;
99 
100 /**
101  * INTERNAL ONLY
102  *
103  * Forward declaration of @c intercommunicator needed for the "cast"
104  * from a communicator to an intercommunicator.
105  */
106 class intercommunicator;
107 
108 /**
109  * INTERNAL ONLY
110  *
111  * Forward declaration of @c graph_communicator needed for the "cast"
112  * from a communicator to a graph communicator.
113  */
114 class graph_communicator;
115 
116 /**
117  * @brief A communicator that permits communication and
118  * synchronization among a set of processes.
119  *
120  * The @c communicator class abstracts a set of communicating
121  * processes in MPI. All of the processes that belong to a certain
122  * communicator can determine the size of the communicator, their rank
123  * within the communicator, and communicate with any other processes
124  * in the communicator.
125  */
126 class BOOST_MPI_DECL communicator
127 {
128  public:
129   /**
130    * Build a new Boost.MPI communicator for @c MPI_COMM_WORLD.
131    *
132    * Constructs a Boost.MPI communicator that attaches to @c
133    * MPI_COMM_WORLD. This is the equivalent of constructing with
134    * @c (MPI_COMM_WORLD, comm_attach).
135    */
136   communicator();
137 
138   /**
139    * Build a new Boost.MPI communicator based on the MPI communicator
140    * @p comm.
141    *
142    * @p comm may be any valid MPI communicator. If @p comm is
143    * MPI_COMM_NULL, an empty communicator (that cannot be used for
144    * communication) is created and the @p kind parameter is
145    * ignored. Otherwise, the @p kind parameters determines how the
146    * Boost.MPI communicator will be related to @p comm:
147    *
148    *   - If @p kind is @c comm_duplicate, duplicate @c comm to create
149    *   a new communicator. This new communicator will be freed when
150    *   the Boost.MPI communicator (and all copies of it) is destroyed.
151    *   This option is only permitted if @p comm is a valid MPI
152    *   intracommunicator or if the underlying MPI implementation
153    *   supports MPI 2.0 (which supports duplication of
154    *   intercommunicators).
155    *
156    *   - If @p kind is @c comm_take_ownership, take ownership of @c
157    *   comm. It will be freed automatically when all of the Boost.MPI
158    *   communicators go out of scope. This option must not be used
159    *   when @c comm is MPI_COMM_WORLD.
160    *
161    *   - If @p kind is @c comm_attach, this Boost.MPI communicator
162    *   will reference the existing MPI communicator @p comm but will
163    *   not free @p comm when the Boost.MPI communicator goes out of
164    *   scope. This option should only be used when the communicator is
165    *   managed by the user or MPI library (e.g., MPI_COMM_WORLD).
166    */
167   communicator(const MPI_Comm& comm, comm_create_kind kind);
168 
169   /**
170    * Build a new Boost.MPI communicator based on a subgroup of another
171    * MPI communicator.
172    *
173    * This routine will construct a new communicator containing all of
174    * the processes from communicator @c comm that are listed within
175    * the group @c subgroup. Equivalent to @c MPI_Comm_create.
176    *
177    * @param comm An MPI communicator.
178    *
179    * @param subgroup A subgroup of the MPI communicator, @p comm, for
180    * which we will construct a new communicator.
181    */
182   communicator(const communicator& comm, const boost::mpi::group& subgroup);
183 
184   /**
185    * @brief Determine the rank of the executing process in a
186    * communicator.
187    *
188    * This routine is equivalent to @c MPI_Comm_rank.
189    *
190    *   @returns The rank of the process in the communicator, which
191    *   will be a value in [0, size())
192    */
193   int rank() const;
194 
195   /**
196    * @brief Determine the number of processes in a communicator.
197    *
198    * This routine is equivalent to @c MPI_Comm_size.
199    *
200    *   @returns The number of processes in the communicator.
201    */
202   int size() const;
203 
204   /**
205    * This routine constructs a new group whose members are the
206    * processes within this communicator. Equivalent to
207    * calling @c MPI_Comm_group.
208    */
209   boost::mpi::group group() const;
210 
211   // ----------------------------------------------------------------
212   // Point-to-point communication
213   // ----------------------------------------------------------------
214 
215   /**
216    *  @brief Send data to another process.
217    *
218    *  This routine executes a potentially blocking send with tag @p tag
219    *  to the process with rank @p dest. It can be received by the
220    *  destination process with a matching @c recv call.
221    *
222    *  The given @p value must be suitable for transmission over
223    *  MPI. There are several classes of types that meet these
224    *  requirements:
225    *
226    *    - Types with mappings to MPI data types: If @c
227    *    is_mpi_datatype<T> is convertible to @c mpl::true_, then @p
228    *    value will be transmitted using the MPI data type
229    *    @c get_mpi_datatype<T>(). All primitive C++ data types that have
230    *    MPI equivalents, e.g., @c int, @c float, @c char, @c double,
231    *    etc., have built-in mappings to MPI data types. You may turn a
232    *    Serializable type with fixed structure into an MPI data type by
233    *    specializing @c is_mpi_datatype for your type.
234    *
235    *    - Serializable types: Any type that provides the @c serialize()
236    *    functionality required by the Boost.Serialization library can be
237    *    transmitted and received.
238    *
239    *    - Packed archives and skeletons: Data that has been packed into
240    *    an @c mpi::packed_oarchive or the skeletons of data that have
241    *    been backed into an @c mpi::packed_skeleton_oarchive can be
242    *    transmitted, but will be received as @c mpi::packed_iarchive and
243    *    @c mpi::packed_skeleton_iarchive, respectively, to allow the
244    *    values (or skeletons) to be extracted by the destination process.
245    *
246    *    - Content: Content associated with a previously-transmitted
247    *    skeleton can be transmitted by @c send and received by @c
248    *    recv. The receiving process may only receive content into the
249    *    content of a value that has been constructed with the matching
250    *    skeleton.
251    *
252    *  For types that have mappings to an MPI data type (including the
253    *  concent of a type), an invocation of this routine will result in
254    *  a single MPI_Send call. For variable-length data, e.g.,
255    *  serialized types and packed archives, two messages will be sent
256    *  via MPI_Send: one containing the length of the data and the
257    *  second containing the data itself. Note that the transmission
258    *  mode for variable-length data is an implementation detail that
259    *  is subject to change.
260    *
261    *  @param dest The rank of the remote process to which the data
262    *  will be sent.
263    *
264    *  @param tag The tag that will be associated with this message. Tags
265    *  may be any integer between zero and an implementation-defined
266    *  upper limit. This limit is accessible via @c environment::max_tag().
267    *
268    *  @param value The value that will be transmitted to the
269    *  receiver. The type @c T of this value must meet the aforementioned
270    *  criteria for transmission.
271    */
272   template<typename T>
273   void send(int dest, int tag, const T& value) const;
274 
275   /**
276    *  @brief Send the skeleton of an object.
277    *
278    *  This routine executes a potentially blocking send with tag @p
279    *  tag to the process with rank @p dest. It can be received by the
280    *  destination process with a matching @c recv call. This variation
281    *  on @c send will be used when a send of a skeleton is explicitly
282    *  requested via code such as:
283    *
284    *  @code
285    *    comm.send(dest, tag, skeleton(object));
286    *  @endcode
287    *
288    *  The semantics of this routine are equivalent to that of sending
289    *  a @c packed_skeleton_oarchive storing the skeleton of the @c
290    *  object.
291    *
292    *  @param dest The rank of the remote process to which the skeleton
293    *  will be sent.
294    *
295    *  @param tag The tag that will be associated with this message. Tags
296    *  may be any integer between zero and an implementation-defined
297    *  upper limit. This limit is accessible via @c environment::max_tag().
298    *
299    *  @param proxy The @c skeleton_proxy containing a reference to the
300    *  object whose skeleton will be transmitted.
301    *
302    */
303   template<typename T>
304   void send(int dest, int tag, const skeleton_proxy<T>& proxy) const;
305 
306   /**
307    *  @brief Send an array of values to another process.
308    *
309    *  This routine executes a potentially blocking send of an array of
310    *  data with tag @p tag to the process with rank @p dest. It can be
311    *  received by the destination process with a matching array @c
312    *  recv call.
313    *
314    *  If @c T is an MPI datatype, an invocation of this routine will
315    *  be mapped to a single call to MPI_Send, using the datatype @c
316    *  get_mpi_datatype<T>().
317    *
318    *  @param dest The process rank of the remote process to which
319    *  the data will be sent.
320    *
321    *  @param tag The tag that will be associated with this message. Tags
322    *  may be any integer between zero and an implementation-defined
323    *  upper limit. This limit is accessible via @c environment::max_tag().
324    *
325    *  @param values The array of values that will be transmitted to the
326    *  receiver. The type @c T of these values must be mapped to an MPI
327    *  data type.
328    *
329    *  @param n The number of values stored in the array. The destination
330    *  process must call receive with at least this many elements to
331    *  correctly receive the message.
332    */
333   template<typename T>
334   void send(int dest, int tag, const T* values, int n) const;
335 
336   /**
337    *  @brief Send a message to another process without any data.
338    *
339    *  This routine executes a potentially blocking send of a message
340    *  to another process. The message contains no extra data, and can
341    *  therefore only be received by a matching call to @c recv().
342    *
343    *  @param dest The process rank of the remote process to which
344    *  the message will be sent.
345    *
346    *  @param tag The tag that will be associated with this message. Tags
347    *  may be any integer between zero and an implementation-defined
348    *  upper limit. This limit is accessible via @c environment::max_tag().
349    *
350    */
351   void send(int dest, int tag) const;
352 
353   /**
354    * @brief Receive data from a remote process.
355    *
356    * This routine blocks until it receives a message from the process @p
357    * source with the given @p tag. The type @c T of the @p value must be
358    * suitable for transmission over MPI, which includes serializable
359    * types, types that can be mapped to MPI data types (including most
360    * built-in C++ types), packed MPI archives, skeletons, and content
361    * associated with skeletons; see the documentation of @c send for a
362    * complete description.
363    *
364    *   @param source The process that will be sending data. This will
365    *   either be a process rank within the communicator or the
366    *   constant @c any_source, indicating that we can receive the
367    *   message from any process.
368    *
369    *   @param tag The tag that matches a particular kind of message sent
370    *   by the source process. This may be any tag value permitted by @c
371    *   send. Alternatively, the argument may be the constant @c any_tag,
372    *   indicating that this receive matches a message with any tag.
373    *
374    *   @param value Will contain the value of the message after a
375    *   successful receive. The type of this value must match the value
376    *   transmitted by the sender, unless the sender transmitted a packed
377    *   archive or skeleton: in these cases, the sender transmits a @c
378    *   packed_oarchive or @c packed_skeleton_oarchive and the
379    *   destination receives a @c packed_iarchive or @c
380    *   packed_skeleton_iarchive, respectively.
381    *
382    *   @returns Information about the received message.
383    */
384   template<typename T>
385   status recv(int source, int tag, T& value) const;
386 
387   /**
388    *  @brief Receive a skeleton from a remote process.
389    *
390    *  This routine blocks until it receives a message from the process @p
391    *  source with the given @p tag containing a skeleton.
392    *
393    *  @param source The process that will be sending data. This will
394    *  either be a process rank within the communicator or the constant
395    *  @c any_source, indicating that we can receive the message from
396    *  any process.
397    *
398    *  @param tag The tag that matches a particular kind of message
399    *  sent by the source process. This may be any tag value permitted
400    *  by @c send. Alternatively, the argument may be the constant @c
401    *  any_tag, indicating that this receive matches a message with any
402    *  tag.
403    *
404    *  @param proxy The @c skeleton_proxy containing a reference to the
405    *  object that will be reshaped to match the received skeleton.
406    *
407    *  @returns Information about the received message.
408    */
409   template<typename T>
410   status recv(int source, int tag, const skeleton_proxy<T>& proxy) const;
411 
412   /**
413    *  @brief Receive a skeleton from a remote process.
414    *
415    *  This routine blocks until it receives a message from the process @p
416    *  source with the given @p tag containing a skeleton.
417    *
418    *  @param source The process that will be sending data. This will
419    *  either be a process rank within the communicator or the constant
420    *  @c any_source, indicating that we can receive the message from
421    *  any process.
422    *
423    *  @param tag The tag that matches a particular kind of message
424    *  sent by the source process. This may be any tag value permitted
425    *  by @c send. Alternatively, the argument may be the constant @c
426    *  any_tag, indicating that this receive matches a message with any
427    *  tag.
428    *
429    *  @param proxy The @c skeleton_proxy containing a reference to the
430    *  object that will be reshaped to match the received skeleton.
431    *
432    *  @returns Information about the received message.
433    */
434   template<typename T>
435   status recv(int source, int tag, skeleton_proxy<T>& proxy) const;
436 
437   /**
438    * @brief Receive an array of values from a remote process.
439    *
440    * This routine blocks until it receives an array of values from the
441    * process @p source with the given @p tag. If the type @c T is
442    *
443    *   @param source The process that will be sending data. This will
444    *   either be a process rank within the communicator or the
445    *   constant @c any_source, indicating that we can receive the
446    *   message from any process.
447    *
448    *   @param tag The tag that matches a particular kind of message sent
449    *   by the source process. This may be any tag value permitted by @c
450    *   send. Alternatively, the argument may be the constant @c any_tag,
451    *   indicating that this receive matches a message with any tag.
452    *
453    *   @param values Will contain the values in the message after a
454    *   successful receive. The type of these elements must match the
455    *   type of the elements transmitted by the sender.
456    *
457    *   @param n The number of values that can be stored into the @p
458    *   values array. This shall not be smaller than the number of
459    *   elements transmitted by the sender.
460    *
461    *   @throws std::range_error if the message to be received contains
462    *   more than @p n values.
463    *
464    *   @returns Information about the received message.
465    */
466   template<typename T>
467   status recv(int source, int tag, T* values, int n) const;
468 
469   /**
470    *  @brief Receive a message from a remote process without any data.
471    *
472    *  This routine blocks until it receives a message from the process
473    *  @p source with the given @p tag.
474    *
475    *  @param source The process that will be sending the message. This
476    *  will either be a process rank within the communicator or the
477    *  constant @c any_source, indicating that we can receive the
478    *  message from any process.
479    *
480    *  @param tag The tag that matches a particular kind of message
481    *  sent by the source process. This may be any tag value permitted
482    *  by @c send. Alternatively, the argument may be the constant @c
483    *  any_tag, indicating that this receive matches a message with any
484    *  tag.
485    *
486    *  @returns Information about the received message.
487    */
488   status recv(int source, int tag) const;
489 
490   /** @brief Send a message to remote process nd receive another message
491    *  from another process.
492    */
493   template<typename T>
494   status sendrecv(int dest, int stag, const T& sval, int src, int rtag, T& rval) const;
495 
496   /**
497    *  @brief Send a message to a remote process without blocking.
498    *
499    *  The @c isend method is functionality identical to the @c send
500    *  method and transmits data in the same way, except that @c isend
501    *  will not block while waiting for the data to be
502    *  transmitted. Instead, a request object will be immediately
503    *  returned, allowing one to query the status of the communication
504    *  or wait until it has completed.
505    *
506    *  @param dest The rank of the remote process to which the data
507    *  will be sent.
508    *
509    *  @param tag The tag that will be associated with this message. Tags
510    *  may be any integer between zero and an implementation-defined
511    *  upper limit. This limit is accessible via @c environment::max_tag().
512    *
513    *  @param value The value that will be transmitted to the
514    *  receiver. The type @c T of this value must meet the aforementioned
515    *  criteria for transmission.
516    *
517    *  @returns a @c request object that describes this communication.
518    */
519   template<typename T>
520   request isend(int dest, int tag, const T& value) const;
521 
522   /**
523    *  @brief Send the skeleton of an object without blocking.
524    *
525    *  This routine is functionally identical to the @c send method for
526    *  @c skeleton_proxy objects except that @c isend will not block
527    *  while waiting for the data to be transmitted. Instead, a request
528    *  object will be immediately returned, allowing one to query the
529    *  status of the communication or wait until it has completed.
530    *
531    *  The semantics of this routine are equivalent to a non-blocking
532    *  send of a @c packed_skeleton_oarchive storing the skeleton of
533    *  the @c object.
534    *
535    *  @param dest The rank of the remote process to which the skeleton
536    *  will be sent.
537    *
538    *  @param tag The tag that will be associated with this message. Tags
539    *  may be any integer between zero and an implementation-defined
540    *  upper limit. This limit is accessible via @c environment::max_tag().
541    *
542    *  @param proxy The @c skeleton_proxy containing a reference to the
543    *  object whose skeleton will be transmitted.
544    *
545    *  @returns a @c request object that describes this communication.
546    */
547   template<typename T>
548   request isend(int dest, int tag, const skeleton_proxy<T>& proxy) const;
549 
550   /**
551    *  @brief Send an array of values to another process without
552    *  blocking.
553    *
554    *  This routine is functionally identical to the @c send method for
555    *  arrays except that @c isend will not block while waiting for the
556    *  data to be transmitted. Instead, a request object will be
557    *  immediately returned, allowing one to query the status of the
558    *  communication or wait until it has completed.
559    *
560    *  @param dest The process rank of the remote process to which
561    *  the data will be sent.
562    *
563    *  @param tag The tag that will be associated with this message. Tags
564    *  may be any integer between zero and an implementation-defined
565    *  upper limit. This limit is accessible via @c environment::max_tag().
566    *
567    *  @param values The array of values that will be transmitted to the
568    *  receiver. The type @c T of these values must be mapped to an MPI
569    *  data type.
570    *
571    *  @param n The number of values stored in the array. The destination
572    *  process must call receive with at least this many elements to
573    *  correctly receive the message.
574    *
575    *  @returns a @c request object that describes this communication.
576    */
577   template<typename T>
578   request isend(int dest, int tag, const T* values, int n) const;
579 
580   /**
581    *  @brief Send a message to another process without any data
582    *  without blocking.
583    *
584    *  This routine is functionally identical to the @c send method for
585    *  sends with no data, except that @c isend will not block while
586    *  waiting for the message to be transmitted. Instead, a request
587    *  object will be immediately returned, allowing one to query the
588    *  status of the communication or wait until it has completed.
589    *
590    *  @param dest The process rank of the remote process to which
591    *  the message will be sent.
592    *
593    *  @param tag The tag that will be associated with this message. Tags
594    *  may be any integer between zero and an implementation-defined
595    *  upper limit. This limit is accessible via @c environment::max_tag().
596    *
597    *
598    *  @returns a @c request object that describes this communication.
599    */
600   request isend(int dest, int tag) const;
601 
602   /**
603    *  @brief Prepare to receive a message from a remote process.
604    *
605    *  The @c irecv method is functionally identical to the @c recv
606    *  method and receive data in the same way, except that @c irecv
607    *  will not block while waiting for data to be
608    *  transmitted. Instead, it immediately returns a request object
609    *  that allows one to query the status of the receive or wait until
610    *  it has completed.
611    *
612    *   @param source The process that will be sending data. This will
613    *   either be a process rank within the communicator or the
614    *   constant @c any_source, indicating that we can receive the
615    *   message from any process.
616    *
617    *   @param tag The tag that matches a particular kind of message sent
618    *   by the source process. This may be any tag value permitted by @c
619    *   send. Alternatively, the argument may be the constant @c any_tag,
620    *   indicating that this receive matches a message with any tag.
621    *
622    *   @param value Will contain the value of the message after a
623    *   successful receive. The type of this value must match the value
624    *   transmitted by the sender, unless the sender transmitted a packed
625    *   archive or skeleton: in these cases, the sender transmits a @c
626    *   packed_oarchive or @c packed_skeleton_oarchive and the
627    *   destination receives a @c packed_iarchive or @c
628    *   packed_skeleton_iarchive, respectively.
629    *
630    *   @returns a @c request object that describes this communication.
631    */
632   template<typename T>
633   request irecv(int source, int tag, T& value) const;
634 
635   /**
636    * @brief Initiate receipt of an array of values from a remote process.
637    *
638    * This routine initiates a receive operation for an array of values
639    * transmitted by process @p source with the given @p tag.
640    *
641    *    @param source The process that will be sending data. This will
642    *    either be a process rank within the communicator or the
643    *    constant @c any_source, indicating that we can receive the
644    *    message from any process.
645    *
646    *    @param tag The tag that matches a particular kind of message sent
647    *    by the source process. This may be any tag value permitted by @c
648    *    send. Alternatively, the argument may be the constant @c any_tag,
649    *    indicating that this receive matches a message with any tag.
650    *
651    *    @param values Will contain the values in the message after a
652    *    successful receive. The type of these elements must match the
653    *    type of the elements transmitted by the sender.
654    *
655    *    @param n The number of values that can be stored into the @p
656    *    values array. This shall not be smaller than the number of
657    *    elements transmitted by the sender.
658    *
659    *    @returns a @c request object that describes this communication.
660    */
661   template<typename T>
662   request irecv(int source, int tag, T* values, int n) const;
663 
664   /**
665    *  @brief Initiate receipt of a message from a remote process that
666    *  carries no data.
667    *
668    *  This routine initiates a receive operation for a message from
669    *  process @p source with the given @p tag that carries no data.
670    *
671    *    @param source The process that will be sending the message. This
672    *    will either be a process rank within the communicator or the
673    *    constant @c any_source, indicating that we can receive the
674    *    message from any process.
675    *
676    *    @param tag The tag that matches a particular kind of message
677    *    sent by the source process. This may be any tag value permitted
678    *    by @c send. Alternatively, the argument may be the constant @c
679    *    any_tag, indicating that this receive matches a message with any
680    *    tag.
681    *
682    *    @returns a @c request object that describes this communication.
683    */
684   request irecv(int source, int tag) const;
685 
686   /**
687    * @brief Waits until a message is available to be received.
688    *
689    * This operation waits until a message matching (@p source, @p tag)
690    * is available to be received. It then returns information about
691    * that message. The functionality is equivalent to @c MPI_Probe. To
692    * check if a message is available without blocking, use @c iprobe.
693    *
694    *   @param source Determine if there is a message available from
695    *   this rank. If @c any_source, then the message returned may come
696    *   from any source.
697    *
698    *   @param tag Determine if there is a message available with the
699    *   given tag. If @c any_tag, then the message returned may have any
700    *   tag.
701    *
702    *   @returns Returns information about the first message that
703    *   matches the given criteria.
704    */
705   status probe(int source = any_source, int tag = any_tag) const;
706 
707   /**
708    * @brief Determine if a message is available to be received.
709    *
710    * This operation determines if a message matching (@p source, @p
711    * tag) is available to be received. If so, it returns information
712    * about that message; otherwise, it returns immediately with an
713    * empty optional. The functionality is equivalent to @c
714    * MPI_Iprobe. To wait until a message is available, use @c wait.
715    *
716    *   @param source Determine if there is a message available from
717    *   this rank. If @c any_source, then the message returned may come
718    *   from any source.
719    *
720    *   @param tag Determine if there is a message available with the
721    *   given tag. If @c any_tag, then the message returned may have any
722    *   tag.
723    *
724    *   @returns If a matching message is available, returns
725    *   information about that message. Otherwise, returns an empty
726    *   @c boost::optional.
727    */
728   optional<status>
729   iprobe(int source = any_source, int tag = any_tag) const;
730 
731 #ifdef barrier
732   // Linux defines a function-like macro named "barrier". So, we need
733   // to avoid expanding the macro when we define our barrier()
734   // function. However, some C++ parsers (Doxygen, for instance) can't
735   // handle this syntax, so we only use it when necessary.
736   void (barrier)() const;
737 #else
738   /**
739    * @brief Wait for all processes within a communicator to reach the
740    * barrier.
741    *
742    * This routine is a collective operation that blocks each process
743    * until all processes have entered it, then releases all of the
744    * processes "simultaneously". It is equivalent to @c MPI_Barrier.
745    */
746   void barrier() const;
747 #endif
748 
749   /** @brief Determine if this communicator is valid for
750    * communication.
751    *
752    * Evaluates @c true in a boolean context if this communicator is
753    * valid for communication, i.e., does not represent
754    * MPI_COMM_NULL. Otherwise, evaluates @c false.
755    */
operator bool() const756   operator bool() const { return (bool)comm_ptr; }
757 
758   /**
759    * @brief Access the MPI communicator associated with a Boost.MPI
760    * communicator.
761    *
762    * This routine permits the implicit conversion from a Boost.MPI
763    * communicator to an MPI communicator.
764    *
765    *   @returns The associated MPI communicator.
766    */
767   operator MPI_Comm() const;
768 
769   /**
770    * Split the communicator into multiple, disjoint communicators
771    * each of which is based on a particular color. This is a
772    * collective operation that returns a new communicator that is a
773    * subgroup of @p this. This routine is functionally equivalent to
774    * @c MPI_Comm_split.
775    *
776    *   @param color The color of this process. All processes with the
777    *   same @p color value will be placed into the same group.
778    *
779    *   @returns A new communicator containing all of the processes in
780    *   @p this that have the same @p color.
781    */
782   communicator split(int color) const;
783 
784   /**
785    * Split the communicator into multiple, disjoint communicators
786    * each of which is based on a particular color. This is a
787    * collective operation that returns a new communicator that is a
788    * subgroup of @p this. This routine is functionally equivalent to
789    * @c MPI_Comm_split.
790    *
791    *   @param color The color of this process. All processes with the
792    *   same @p color value will be placed into the same group.
793    *
794    *   @param key A key value that will be used to determine the
795    *   ordering of processes with the same color in the resulting
796    *   communicator. If omitted, the rank of the processes in @p this
797    *   will determine the ordering of processes in the resulting
798    *   group.
799    *
800    *   @returns A new communicator containing all of the processes in
801    *   @p this that have the same @p color.
802    */
803   communicator split(int color, int key) const;
804 
805   /**
806    * Determine if the communicator is in fact an intercommunicator
807    * and, if so, return that intercommunicator.
808    *
809    * @returns an @c optional containing the intercommunicator, if this
810    * communicator is in fact an intercommunicator. Otherwise, returns
811    * an empty @c optional.
812    */
813   optional<intercommunicator> as_intercommunicator() const;
814 
815   /**
816    * Determine if the communicator has a graph topology and, if so,
817    * return that @c graph_communicator. Even though the communicators
818    * have different types, they refer to the same underlying
819    * communication space and can be used interchangeably for
820    * communication.
821    *
822    * @returns an @c optional containing the graph communicator, if this
823    * communicator does in fact have a graph topology. Otherwise, returns
824    * an empty @c optional.
825    */
826   optional<graph_communicator> as_graph_communicator() const;
827 
828   /**
829    * Determines whether this communicator has a Cartesian topology.
830    */
831   bool has_cartesian_topology() const;
832 
833 #if 0
834   template<typename Extents>
835   communicator
836   with_cartesian_topology(const Extents& extents,
837                           bool periodic = false,
838                           bool reorder = false) const;
839 
840   template<typename DimInputIterator, typename PeriodicInputIterator>
841   communicator
842   with_cartesian_topology(DimInputIterator first_dim,
843                           DimInputIterator last_dim,
844                           PeriodicInputIterator first_periodic,
845                           bool reorder = false);
846 
847   template<typename Allocator, std::size_t NumDims>
848   communicator
849   with_cartesian_topology(const multi_array<bool, NumDims, Allocator>& periods,
850                           bool reorder = false);
851 #endif
852 
853   /** Abort all tasks in the group of this communicator.
854    *
855    *  Makes a "best attempt" to abort all of the tasks in the group of
856    *  this communicator. Depending on the underlying MPI
857    *  implementation, this may either abort the entire program (and
858    *  possibly return @p errcode to the environment) or only abort
859    *  some processes, allowing the others to continue. Consult the
860    *  documentation for your MPI implementation. This is equivalent to
861    *  a call to @c MPI_Abort
862    *
863    *  @param errcode The error code to return from aborted processes.
864    *  @returns Will not return.
865    */
866   void abort(int errcode) const;
867 
868  protected:
869 
870   /**
871    * INTERNAL ONLY
872    *
873    * Implementation of sendrecv for mpi type.
874    */
875   template<typename T>
876   status sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval,
877                        mpl::true_) const;
878 
879   /**
880    * INTERNAL ONLY
881    *
882    * Implementation of sendrecv for complex types, which must be passed as archives.
883    */
884   template<typename T>
885   status sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval,
886                        mpl::false_) const;
887 
888   /**
889    * INTERNAL ONLY
890    *
891    * Function object that frees an MPI communicator and deletes the
892    * memory associated with it. Intended to be used as a deleter with
893    * shared_ptr.
894    */
895   struct comm_free
896   {
operator ()boost::mpi::communicator::comm_free897     void operator()(MPI_Comm* comm) const
898     {
899       BOOST_ASSERT( comm != 0 );
900       BOOST_ASSERT(*comm != MPI_COMM_NULL);
901       int finalized;
902       BOOST_MPI_CHECK_RESULT(MPI_Finalized, (&finalized));
903       if (!finalized)
904         BOOST_MPI_CHECK_RESULT(MPI_Comm_free, (comm));
905       delete comm;
906     }
907   };
908 
909 
910   /**
911    * INTERNAL ONLY
912    *
913    * We're sending a type that has an associated MPI datatype, so we
914    * map directly to that datatype.
915    */
916   template<typename T>
917   void send_impl(int dest, int tag, const T& value, mpl::true_) const;
918 
919   /**
920    * INTERNAL ONLY
921    *
922    * We're sending a type that does not have an associated MPI
923    * datatype, so it must be serialized then sent as MPI_PACKED data,
924    * to be deserialized on the receiver side.
925    */
926   template<typename T>
927   void send_impl(int dest, int tag, const T& value, mpl::false_) const;
928 
929   /**
930    * INTERNAL ONLY
931    *
932    * We're sending an array of a type that has an associated MPI
933    * datatype, so we map directly to that datatype.
934    */
935   template<typename T>
936   void
937   array_send_impl(int dest, int tag, const T* values, int n, mpl::true_) const;
938 
939   /**
940    * INTERNAL ONLY
941    *
942    * We're sending an array of a type that does not have an associated
943    * MPI datatype, so it must be serialized then sent as MPI_PACKED
944    * data, to be deserialized on the receiver side.
945    */
946   template<typename T>
947   void
948   array_send_impl(int dest, int tag, const T* values, int n,
949                   mpl::false_) const;
950 
951   /**
952    * INTERNAL ONLY
953    *
954    * We're sending a type that has an associated MPI datatype, so we
955    * map directly to that datatype.
956    */
957   template<typename T>
958   request isend_impl(int dest, int tag, const T& value, mpl::true_) const;
959 
960   /**
961    * INTERNAL ONLY
962    *
963    * We're sending a type that does not have an associated MPI
964    * datatype, so it must be serialized then sent as MPI_PACKED data,
965    * to be deserialized on the receiver side.
966    */
967   template<typename T>
968   request isend_impl(int dest, int tag, const T& value, mpl::false_) const;
969 
970   /**
971    * INTERNAL ONLY
972    *
973    * We're sending an array of a type that has an associated MPI
974    * datatype, so we map directly to that datatype.
975    */
976   template<typename T>
977   request
978   array_isend_impl(int dest, int tag, const T* values, int n,
979                    mpl::true_) const;
980 
981   /**
982    * INTERNAL ONLY
983    *
984    * We're sending an array of a type that does not have an associated
985    * MPI datatype, so it must be serialized then sent as MPI_PACKED
986    * data, to be deserialized on the receiver side.
987    */
988   template<typename T>
989   request
990   array_isend_impl(int dest, int tag, const T* values, int n,
991                    mpl::false_) const;
992 
993   /**
994    * INTERNAL ONLY
995    *
996    * We're receiving a type that has an associated MPI datatype, so we
997    * map directly to that datatype.
998    */
999   template<typename T>
1000   status recv_impl(int source, int tag, T& value, mpl::true_) const;
1001 
1002   /**
1003    * INTERNAL ONLY
1004    *
1005    * We're receiving a type that does not have an associated MPI
1006    * datatype, so it must have been serialized then sent as
1007    * MPI_PACKED. We'll receive it and then deserialize.
1008    */
1009   template<typename T>
1010   status recv_impl(int source, int tag, T& value, mpl::false_) const;
1011 
1012   /**
1013    * INTERNAL ONLY
1014    *
1015    * We're receiving an array of a type that has an associated MPI
1016    * datatype, so we map directly to that datatype.
1017    */
1018   template<typename T>
1019   status
1020   array_recv_impl(int source, int tag, T* values, int n, mpl::true_) const;
1021 
1022   /**
1023    * INTERNAL ONLY
1024    *
1025    * We're receiving a type that does not have an associated MPI
1026    * datatype, so it must have been serialized then sent as
1027    * MPI_PACKED. We'll receive it and then deserialize.
1028    */
1029   template<typename T>
1030   status
1031   array_recv_impl(int source, int tag, T* values, int n, mpl::false_) const;
1032 
1033   /**
1034    * INTERNAL ONLY
1035    *
1036    * We're receiving a type that has an associated MPI datatype, so we
1037    * map directly to that datatype.
1038    */
1039   template<typename T>
1040   request irecv_impl(int source, int tag, T& value, mpl::true_) const;
1041 
1042   /**
1043    * INTERNAL ONLY
1044    *
1045    * We're receiving a type that does not have an associated MPI
1046    * datatype, so it must have been serialized then sent as
1047    * MPI_PACKED. We'll receive it and then deserialize.
1048    */
1049   template<typename T>
1050   request irecv_impl(int source, int tag, T& value, mpl::false_) const;
1051 
1052   /**
1053    * INTERNAL ONLY
1054    *
1055    * We're receiving a type that has an associated MPI datatype, so we
1056    * map directly to that datatype.
1057    */
1058   template<typename T>
1059   request
1060   array_irecv_impl(int source, int tag, T* values, int n, mpl::true_) const;
1061 
1062   /**
1063    * INTERNAL ONLY
1064    *
1065    * We're receiving a type that does not have an associated MPI
1066    * datatype, so it must have been serialized then sent as
1067    * MPI_PACKED. We'll receive it and then deserialize.
1068    */
1069   template<typename T>
1070   request
1071   array_irecv_impl(int source, int tag, T* values, int n, mpl::false_) const;
1072 
1073   shared_ptr<MPI_Comm> comm_ptr;
1074 };
1075 
1076 /**
1077  * @brief Determines whether two communicators are identical.
1078  *
1079  * Equivalent to calling @c MPI_Comm_compare and checking whether the
1080  * result is @c MPI_IDENT.
1081  *
1082  * @returns True when the two communicators refer to the same
1083  * underlying MPI communicator.
1084  */
1085 BOOST_MPI_DECL bool operator==(const communicator& comm1, const communicator& comm2);
1086 
1087 /**
1088  * @brief Determines whether two communicators are different.
1089  *
1090  * @returns @c !(comm1 == comm2)
1091  */
operator !=(const communicator & comm1,const communicator & comm2)1092 inline bool operator!=(const communicator& comm1, const communicator& comm2)
1093 {
1094   return !(comm1 == comm2);
1095 }
1096 
1097 
1098 /************************************************************************
1099  * Implementation details                                               *
1100  ************************************************************************/
1101 // Count elements in a message
1102 template<typename T>
count() const1103 inline optional<int> status::count() const
1104 {
1105   return count_impl<T>(is_mpi_datatype<T>());
1106 }
1107 
1108 template<typename T>
count_impl(mpl::true_) const1109 optional<int> status::count_impl(mpl::true_) const
1110 {
1111   if (m_count != -1)
1112     return m_count;
1113 
1114   int return_value;
1115   BOOST_MPI_CHECK_RESULT(MPI_Get_count,
1116                          (&m_status, get_mpi_datatype<T>(T()), &return_value));
1117   if (return_value == MPI_UNDEFINED)
1118     return optional<int>();
1119   else
1120     /* Cache the result. */
1121     return m_count = return_value;
1122 }
1123 
1124 template<typename T>
count_impl(mpl::false_) const1125 inline optional<int> status::count_impl(mpl::false_) const
1126 {
1127   if (m_count == -1)
1128     return optional<int>();
1129   else
1130     return m_count;
1131 }
1132 
1133 // We're sending a type that has an associated MPI datatype, so we
1134 // map directly to that datatype.
1135 template<typename T>
1136 void
send_impl(int dest,int tag,const T & value,mpl::true_) const1137 communicator::send_impl(int dest, int tag, const T& value, mpl::true_) const
1138 {
1139   BOOST_MPI_CHECK_RESULT(MPI_Send,
1140                          (const_cast<T*>(&value), 1, get_mpi_datatype<T>(value),
1141                           dest, tag, MPI_Comm(*this)));
1142 }
1143 
1144 // We're sending a type that does not have an associated MPI
1145 // datatype, so it must be serialized then sent as MPI_PACKED data,
1146 // to be deserialized on the receiver side.
1147 template<typename T>
1148 void
send_impl(int dest,int tag,const T & value,mpl::false_) const1149 communicator::send_impl(int dest, int tag, const T& value, mpl::false_) const
1150 {
1151   packed_oarchive oa(*this);
1152   oa << value;
1153   send(dest, tag, oa);
1154 }
1155 
1156 // Single-element receive may either send the element directly or
1157 // serialize it via a buffer.
1158 template<typename T>
send(int dest,int tag,const T & value) const1159 void communicator::send(int dest, int tag, const T& value) const
1160 {
1161   this->send_impl(dest, tag, value, is_mpi_datatype<T>());
1162 }
1163 
1164 // We're sending an array of a type that has an associated MPI
1165 // datatype, so we map directly to that datatype.
1166 template<typename T>
1167 void
array_send_impl(int dest,int tag,const T * values,int n,mpl::true_) const1168 communicator::array_send_impl(int dest, int tag, const T* values, int n,
1169                               mpl::true_) const
1170 {
1171   BOOST_MPI_CHECK_RESULT(MPI_Send,
1172                          (const_cast<T*>(values), n,
1173                           get_mpi_datatype<T>(*values),
1174                           dest, tag, MPI_Comm(*this)));
1175 }
1176 
1177 // We're sending an array of a type that does not have an associated
1178 // MPI datatype, so it must be serialized then sent as MPI_PACKED
1179 // data, to be deserialized on the receiver side.
1180 template<typename T>
1181 void
array_send_impl(int dest,int tag,const T * values,int n,mpl::false_) const1182 communicator::array_send_impl(int dest, int tag, const T* values, int n,
1183                               mpl::false_) const
1184 {
1185   packed_oarchive oa(*this);
1186   oa << n << boost::serialization::make_array(values, n);
1187   send(dest, tag, oa);
1188 }
1189 
1190 // Array send must send the elements directly
1191 template<typename T>
send(int dest,int tag,const T * values,int n) const1192 void communicator::send(int dest, int tag, const T* values, int n) const
1193 {
1194   this->array_send_impl(dest, tag, values, n, is_mpi_datatype<T>());
1195 }
1196 
1197 // We're receiving a type that has an associated MPI datatype, so we
1198 // map directly to that datatype.
1199 template<typename T>
recv_impl(int source,int tag,T & value,mpl::true_) const1200 status communicator::recv_impl(int source, int tag, T& value, mpl::true_) const
1201 {
1202   status stat;
1203 
1204   BOOST_MPI_CHECK_RESULT(MPI_Recv,
1205                          (const_cast<T*>(&value), 1,
1206                           get_mpi_datatype<T>(value),
1207                           source, tag, MPI_Comm(*this), &stat.m_status));
1208   return stat;
1209 }
1210 
1211 template<typename T>
1212 status
recv_impl(int source,int tag,T & value,mpl::false_) const1213 communicator::recv_impl(int source, int tag, T& value, mpl::false_) const
1214 {
1215   // Receive the message
1216   packed_iarchive ia(*this);
1217   status stat = recv(source, tag, ia);
1218 
1219   // Deserialize the data in the message
1220   ia >> value;
1221 
1222   return stat;
1223 }
1224 
1225 // Single-element receive may either receive the element directly or
1226 // deserialize it from a buffer.
1227 template<typename T>
recv(int source,int tag,T & value) const1228 status communicator::recv(int source, int tag, T& value) const
1229 {
1230   return this->recv_impl(source, tag, value, is_mpi_datatype<T>());
1231 }
1232 
1233 template<typename T>
1234 status
array_recv_impl(int source,int tag,T * values,int n,mpl::true_) const1235 communicator::array_recv_impl(int source, int tag, T* values, int n,
1236                               mpl::true_) const
1237 {
1238   status stat;
1239   BOOST_MPI_CHECK_RESULT(MPI_Recv,
1240                          (const_cast<T*>(values), n,
1241                           get_mpi_datatype<T>(*values),
1242                           source, tag, MPI_Comm(*this), &stat.m_status));
1243   return stat;
1244 }
1245 
1246 template<typename T>
1247 status
array_recv_impl(int source,int tag,T * values,int n,mpl::false_) const1248 communicator::array_recv_impl(int source, int tag, T* values, int n,
1249                               mpl::false_) const
1250 {
1251   // Receive the message
1252   packed_iarchive ia(*this);
1253   status stat = recv(source, tag, ia);
1254 
1255   // Determine how much data we are going to receive
1256   int count;
1257   ia >> count;
1258 
1259   // Deserialize the data in the message
1260   boost::serialization::array<T> arr(values, count > n? n : count);
1261   ia >> arr;
1262 
1263   if (count > n) {
1264     boost::throw_exception(
1265       std::range_error("communicator::recv: message receive overflow"));
1266   }
1267 
1268   stat.m_count = count;
1269   return stat;
1270 }
1271 
1272 // Array receive must receive the elements directly into a buffer.
1273 template<typename T>
recv(int source,int tag,T * values,int n) const1274 status communicator::recv(int source, int tag, T* values, int n) const
1275 {
1276   return this->array_recv_impl(source, tag, values, n, is_mpi_datatype<T>());
1277 }
1278 
1279 
1280 template<typename T>
sendrecv_impl(int dest,int stag,const T & sval,int src,int rtag,T & rval,mpl::true_) const1281 status communicator::sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval,
1282                                     mpl::true_) const
1283 {
1284   status stat;
1285   BOOST_MPI_CHECK_RESULT(MPI_Sendrecv,
1286                          (const_cast<T*>(&sval), 1,
1287                           get_mpi_datatype<T>(sval),
1288                           dest, stag,
1289                           &rval, 1,
1290                           get_mpi_datatype<T>(rval),
1291                           src, rtag,
1292                           MPI_Comm(*this), &stat.m_status));
1293   return stat;
1294 }
1295 
1296 template<typename T>
sendrecv_impl(int dest,int stag,const T & sval,int src,int rtag,T & rval,mpl::false_) const1297 status communicator::sendrecv_impl(int dest, int stag, const T& sval, int src, int rtag, T& rval,
1298                                    mpl::false_) const
1299 {
1300   int const SEND = 0;
1301   int const RECV = 1;
1302   request srrequests[2];
1303   srrequests[SEND] = this->isend_impl(dest, stag, sval, mpl::false_());
1304   srrequests[RECV] = this->irecv_impl(src,  rtag, rval, mpl::false_());
1305   status srstatuses[2];
1306   wait_all(srrequests, srrequests + 2, srstatuses);
1307   return srstatuses[RECV];
1308 }
1309 
1310 template<typename T>
sendrecv(int dest,int stag,const T & sval,int src,int rtag,T & rval) const1311 status communicator::sendrecv(int dest, int stag, const T& sval, int src, int rtag, T& rval) const
1312 {
1313   return this->sendrecv_impl(dest, stag, sval, src, rtag, rval, is_mpi_datatype<T>());
1314 }
1315 
1316 
1317 // We're sending a type that has an associated MPI datatype, so we
1318 // map directly to that datatype.
1319 template<typename T>
1320 request
isend_impl(int dest,int tag,const T & value,mpl::true_) const1321 communicator::isend_impl(int dest, int tag, const T& value, mpl::true_) const
1322 {
1323   request req;
1324   BOOST_MPI_CHECK_RESULT(MPI_Isend,
1325                          (const_cast<T*>(&value), 1,
1326                           get_mpi_datatype<T>(value),
1327                           dest, tag, MPI_Comm(*this), &req.m_requests[0]));
1328   return req;
1329 }
1330 
1331 // We're sending a type that does not have an associated MPI
1332 // datatype, so it must be serialized then sent as MPI_PACKED data,
1333 // to be deserialized on the receiver side.
1334 template<typename T>
1335 request
isend_impl(int dest,int tag,const T & value,mpl::false_) const1336 communicator::isend_impl(int dest, int tag, const T& value, mpl::false_) const
1337 {
1338   shared_ptr<packed_oarchive> archive(new packed_oarchive(*this));
1339   *archive << value;
1340   request result = isend(dest, tag, *archive);
1341   result.m_data = archive;
1342   return result;
1343 }
1344 
1345 // Single-element receive may either send the element directly or
1346 // serialize it via a buffer.
1347 template<typename T>
isend(int dest,int tag,const T & value) const1348 request communicator::isend(int dest, int tag, const T& value) const
1349 {
1350   return this->isend_impl(dest, tag, value, is_mpi_datatype<T>());
1351 }
1352 
1353 template<typename T>
1354 request
array_isend_impl(int dest,int tag,const T * values,int n,mpl::true_) const1355 communicator::array_isend_impl(int dest, int tag, const T* values, int n,
1356                                mpl::true_) const
1357 {
1358   request req;
1359   BOOST_MPI_CHECK_RESULT(MPI_Isend,
1360                          (const_cast<T*>(values), n,
1361                           get_mpi_datatype<T>(*values),
1362                           dest, tag, MPI_Comm(*this), &req.m_requests[0]));
1363   return req;
1364 }
1365 
1366 template<typename T>
1367 request
array_isend_impl(int dest,int tag,const T * values,int n,mpl::false_) const1368 communicator::array_isend_impl(int dest, int tag, const T* values, int n,
1369                                mpl::false_) const
1370 {
1371   shared_ptr<packed_oarchive> archive(new packed_oarchive(*this));
1372   *archive << n << boost::serialization::make_array(values, n);
1373   request result = isend(dest, tag, *archive);
1374   result.m_data = archive;
1375   return result;
1376 }
1377 
1378 
1379 // Array isend must send the elements directly
1380 template<typename T>
isend(int dest,int tag,const T * values,int n) const1381 request communicator::isend(int dest, int tag, const T* values, int n) const
1382 {
1383   return array_isend_impl(dest, tag, values, n, is_mpi_datatype<T>());
1384 }
1385 
1386 namespace detail {
1387   /**
1388    * Internal data structure that stores everything required to manage
1389    * the receipt of serialized data via a request object.
1390    */
1391   template<typename T>
1392   struct serialized_irecv_data
1393   {
serialized_irecv_databoost::mpi::detail::serialized_irecv_data1394     serialized_irecv_data(const communicator& comm, int source, int tag,
1395                           T& value)
1396       : comm(comm), source(source), tag(tag), ia(comm), value(value)
1397     {
1398     }
1399 
deserializeboost::mpi::detail::serialized_irecv_data1400     void deserialize(status& stat)
1401     {
1402       ia >> value;
1403       stat.m_count = 1;
1404     }
1405 
1406     communicator comm;
1407     int source;
1408     int tag;
1409     std::size_t count;
1410     packed_iarchive ia;
1411     T& value;
1412   };
1413 
1414   template<>
1415   struct serialized_irecv_data<packed_iarchive>
1416   {
serialized_irecv_databoost::mpi::detail::serialized_irecv_data1417     serialized_irecv_data(const communicator& comm, int source, int tag,
1418                           packed_iarchive& ia)
1419       : comm(comm), source(source), tag(tag), ia(ia) { }
1420 
deserializeboost::mpi::detail::serialized_irecv_data1421     void deserialize(status&) { /* Do nothing. */ }
1422 
1423     communicator comm;
1424     int source;
1425     int tag;
1426     std::size_t count;
1427     packed_iarchive& ia;
1428   };
1429 
1430   /**
1431    * Internal data structure that stores everything required to manage
1432    * the receipt of an array of serialized data via a request object.
1433    */
1434   template<typename T>
1435   struct serialized_array_irecv_data
1436   {
serialized_array_irecv_databoost::mpi::detail::serialized_array_irecv_data1437     serialized_array_irecv_data(const communicator& comm, int source, int tag,
1438                                 T* values, int n)
1439       : comm(comm), source(source), tag(tag), ia(comm), values(values), n(n)
1440     {
1441     }
1442 
1443     void deserialize(status& stat);
1444 
1445     communicator comm;
1446     int source;
1447     int tag;
1448     std::size_t count;
1449     packed_iarchive ia;
1450     T* values;
1451     int n;
1452   };
1453 
1454   template<typename T>
deserialize(status & stat)1455   void serialized_array_irecv_data<T>::deserialize(status& stat)
1456   {
1457     // Determine how much data we are going to receive
1458     int count;
1459     ia >> count;
1460 
1461     // Deserialize the data in the message
1462     boost::serialization::array<T> arr(values, count > n? n : count);
1463     ia >> arr;
1464 
1465     if (count > n) {
1466       boost::throw_exception(
1467         std::range_error("communicator::recv: message receive overflow"));
1468     }
1469 
1470     stat.m_count = count;
1471   }
1472 }
1473 
1474 template<typename T>
1475 optional<status>
handle_serialized_irecv(request * self,request_action action)1476 request::handle_serialized_irecv(request* self, request_action action)
1477 {
1478   typedef detail::serialized_irecv_data<T> data_t;
1479   shared_ptr<data_t> data = static_pointer_cast<data_t>(self->m_data);
1480 
1481   if (action == ra_wait) {
1482     status stat;
1483     if (self->m_requests[1] == MPI_REQUEST_NULL) {
1484       // Wait for the count message to complete
1485       BOOST_MPI_CHECK_RESULT(MPI_Wait,
1486                              (self->m_requests, &stat.m_status));
1487       // Resize our buffer and get ready to receive its data
1488       data->ia.resize(data->count);
1489       BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1490                              (data->ia.address(), data->ia.size(), MPI_PACKED,
1491                               stat.source(), stat.tag(),
1492                               MPI_Comm(data->comm), self->m_requests + 1));
1493     }
1494 
1495     // Wait until we have received the entire message
1496     BOOST_MPI_CHECK_RESULT(MPI_Wait,
1497                            (self->m_requests + 1, &stat.m_status));
1498 
1499     data->deserialize(stat);
1500     return stat;
1501   } else if (action == ra_test) {
1502     status stat;
1503     int flag = 0;
1504 
1505     if (self->m_requests[1] == MPI_REQUEST_NULL) {
1506       // Check if the count message has completed
1507       BOOST_MPI_CHECK_RESULT(MPI_Test,
1508                              (self->m_requests, &flag, &stat.m_status));
1509       if (flag) {
1510         // Resize our buffer and get ready to receive its data
1511         data->ia.resize(data->count);
1512         BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1513                                (data->ia.address(), data->ia.size(),MPI_PACKED,
1514                                 stat.source(), stat.tag(),
1515                                 MPI_Comm(data->comm), self->m_requests + 1));
1516       } else
1517         return optional<status>(); // We have not finished yet
1518     }
1519 
1520     // Check if we have received the message data
1521     BOOST_MPI_CHECK_RESULT(MPI_Test,
1522                            (self->m_requests + 1, &flag, &stat.m_status));
1523     if (flag) {
1524       data->deserialize(stat);
1525       return stat;
1526     } else
1527       return optional<status>();
1528   } else {
1529     return optional<status>();
1530   }
1531 }
1532 
1533 template<typename T>
1534 optional<status>
handle_serialized_array_irecv(request * self,request_action action)1535 request::handle_serialized_array_irecv(request* self, request_action action)
1536 {
1537   typedef detail::serialized_array_irecv_data<T> data_t;
1538   shared_ptr<data_t> data = static_pointer_cast<data_t>(self->m_data);
1539 
1540   if (action == ra_wait) {
1541     status stat;
1542     if (self->m_requests[1] == MPI_REQUEST_NULL) {
1543       // Wait for the count message to complete
1544       BOOST_MPI_CHECK_RESULT(MPI_Wait,
1545                              (self->m_requests, &stat.m_status));
1546       // Resize our buffer and get ready to receive its data
1547       data->ia.resize(data->count);
1548       BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1549                              (data->ia.address(), data->ia.size(), MPI_PACKED,
1550                               stat.source(), stat.tag(),
1551                               MPI_Comm(data->comm), self->m_requests + 1));
1552     }
1553 
1554     // Wait until we have received the entire message
1555     BOOST_MPI_CHECK_RESULT(MPI_Wait,
1556                            (self->m_requests + 1, &stat.m_status));
1557 
1558     data->deserialize(stat);
1559     return stat;
1560   } else if (action == ra_test) {
1561     status stat;
1562     int flag = 0;
1563 
1564     if (self->m_requests[1] == MPI_REQUEST_NULL) {
1565       // Check if the count message has completed
1566       BOOST_MPI_CHECK_RESULT(MPI_Test,
1567                              (self->m_requests, &flag, &stat.m_status));
1568       if (flag) {
1569         // Resize our buffer and get ready to receive its data
1570         data->ia.resize(data->count);
1571         BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1572                                (data->ia.address(), data->ia.size(),MPI_PACKED,
1573                                 stat.source(), stat.tag(),
1574                                 MPI_Comm(data->comm), self->m_requests + 1));
1575       } else
1576         return optional<status>(); // We have not finished yet
1577     }
1578 
1579     // Check if we have received the message data
1580     BOOST_MPI_CHECK_RESULT(MPI_Test,
1581                            (self->m_requests + 1, &flag, &stat.m_status));
1582     if (flag) {
1583       data->deserialize(stat);
1584       return stat;
1585     } else
1586       return optional<status>();
1587   } else {
1588     return optional<status>();
1589   }
1590 }
1591 
1592 // We're receiving a type that has an associated MPI datatype, so we
1593 // map directly to that datatype.
1594 template<typename T>
1595 request
irecv_impl(int source,int tag,T & value,mpl::true_) const1596 communicator::irecv_impl(int source, int tag, T& value, mpl::true_) const
1597 {
1598   request req;
1599   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1600                          (const_cast<T*>(&value), 1,
1601                           get_mpi_datatype<T>(value),
1602                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
1603   return req;
1604 }
1605 
1606 template<typename T>
1607 request
irecv_impl(int source,int tag,T & value,mpl::false_) const1608 communicator::irecv_impl(int source, int tag, T& value, mpl::false_) const
1609 {
1610   typedef detail::serialized_irecv_data<T> data_t;
1611   shared_ptr<data_t> data(new data_t(*this, source, tag, value));
1612   request req;
1613   req.m_data = data;
1614   req.m_handler = request::handle_serialized_irecv<T>;
1615 
1616   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1617                          (&data->count, 1,
1618                           get_mpi_datatype<std::size_t>(data->count),
1619                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
1620 
1621   return req;
1622 }
1623 
1624 template<typename T>
1625 request
irecv(int source,int tag,T & value) const1626 communicator::irecv(int source, int tag, T& value) const
1627 {
1628   return this->irecv_impl(source, tag, value, is_mpi_datatype<T>());
1629 }
1630 
1631 template<typename T>
1632 request
array_irecv_impl(int source,int tag,T * values,int n,mpl::true_) const1633 communicator::array_irecv_impl(int source, int tag, T* values, int n,
1634                                mpl::true_) const
1635 {
1636   request req;
1637   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1638                          (const_cast<T*>(values), n,
1639                           get_mpi_datatype<T>(*values),
1640                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
1641   return req;
1642 }
1643 
1644 template<typename T>
1645 request
array_irecv_impl(int source,int tag,T * values,int n,mpl::false_) const1646 communicator::array_irecv_impl(int source, int tag, T* values, int n,
1647                                mpl::false_) const
1648 {
1649   typedef detail::serialized_array_irecv_data<T> data_t;
1650   shared_ptr<data_t> data(new data_t(*this, source, tag, values, n));
1651   request req;
1652   req.m_data = data;
1653   req.m_handler = request::handle_serialized_array_irecv<T>;
1654 
1655   BOOST_MPI_CHECK_RESULT(MPI_Irecv,
1656                          (&data->count, 1,
1657                           get_mpi_datatype<std::size_t>(data->count),
1658                           source, tag, MPI_Comm(*this), &req.m_requests[0]));
1659 
1660   return req;
1661 }
1662 
1663 
1664 // Array receive must receive the elements directly into a buffer.
1665 template<typename T>
irecv(int source,int tag,T * values,int n) const1666 request communicator::irecv(int source, int tag, T* values, int n) const
1667 {
1668   return this->array_irecv_impl(source, tag, values, n, is_mpi_datatype<T>());
1669 }
1670 
1671 /**
1672  * INTERNAL ONLY
1673  */
1674 template<>
1675 BOOST_MPI_DECL void
1676 communicator::send<packed_oarchive>(int dest, int tag,
1677                                     const packed_oarchive& ar) const;
1678 
1679 /**
1680  * INTERNAL ONLY
1681  */
1682 template<>
1683 BOOST_MPI_DECL void
1684 communicator::send<packed_skeleton_oarchive>
1685   (int dest, int tag, const packed_skeleton_oarchive& ar) const;
1686 
1687 /**
1688  * INTERNAL ONLY
1689  */
1690 template<>
1691 BOOST_MPI_DECL void
1692 communicator::send<content>(int dest, int tag, const content& c) const;
1693 
1694 /**
1695  * INTERNAL ONLY
1696  */
1697 template<>
1698 BOOST_MPI_DECL status
1699 communicator::recv<packed_iarchive>(int source, int tag,
1700                                     packed_iarchive& ar) const;
1701 
1702 /**
1703  * INTERNAL ONLY
1704  */
1705 template<>
1706 BOOST_MPI_DECL status
1707 communicator::recv<packed_skeleton_iarchive>
1708   (int source, int tag, packed_skeleton_iarchive& ar) const;
1709 
1710 /**
1711  * INTERNAL ONLY
1712  */
1713 template<>
1714 BOOST_MPI_DECL status
1715 communicator::recv<const content>(int source, int tag,
1716                                   const content& c) const;
1717 
1718 /**
1719  * INTERNAL ONLY
1720  */
1721 template<>
1722 inline status
recv(int source,int tag,content & c) const1723 communicator::recv<content>(int source, int tag,
1724                                   content& c) const
1725 {
1726   return recv<const content>(source,tag,c);
1727 }
1728 
1729 /**
1730  * INTERNAL ONLY
1731  */
1732 template<>
1733 BOOST_MPI_DECL request
1734 communicator::isend<packed_oarchive>(int dest, int tag,
1735                                      const packed_oarchive& ar) const;
1736 
1737 /**
1738  * INTERNAL ONLY
1739  */
1740 template<>
1741 BOOST_MPI_DECL request
1742 communicator::isend<packed_skeleton_oarchive>
1743   (int dest, int tag, const packed_skeleton_oarchive& ar) const;
1744 
1745 /**
1746  * INTERNAL ONLY
1747  */
1748 template<>
1749 BOOST_MPI_DECL request
1750 communicator::isend<content>(int dest, int tag, const content& c) const;
1751 
1752 /**
1753  * INTERNAL ONLY
1754  */
1755 template<>
1756 BOOST_MPI_DECL request
1757 communicator::irecv<packed_skeleton_iarchive>
1758   (int source, int tag, packed_skeleton_iarchive& ar) const;
1759 
1760 /**
1761  * INTERNAL ONLY
1762  */
1763 template<>
1764 BOOST_MPI_DECL request
1765 communicator::irecv<const content>(int source, int tag,
1766                                    const content& c) const;
1767 
1768 /**
1769  * INTERNAL ONLY
1770  */
1771 template<>
1772 inline request
irecv(int source,int tag,content & c) const1773 communicator::irecv<content>(int source, int tag,
1774                              content& c) const
1775 {
1776   return irecv<const content>(source, tag, c);
1777 }
1778 
1779 
1780 } } // end namespace boost::mpi
1781 
1782 // If the user has already included skeleton_and_content.hpp, include
1783 // the code to send/receive skeletons and content.
1784 #ifdef BOOST_MPI_SKELETON_AND_CONTENT_HPP
1785 #  include <boost/mpi/detail/communicator_sc.hpp>
1786 #endif
1787 
1788 #ifdef BOOST_MSVC
1789 #  pragma warning(pop)
1790 #endif
1791 
1792 #endif // BOOST_MPI_COMMUNICATOR_HPP
1793