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
|