annotate DEPENDENCIES/generic/include/boost/mpi/communicator.hpp @ 133:4acb5d8d80b6 tip

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