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