Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/mpi/nonblocking.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 // Copyright (C) 2006 Douglas Gregor <doug.gregor -at- gmail.com>. | |
2 | |
3 // Use, modification and distribution is subject to the Boost Software | |
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
5 // http://www.boost.org/LICENSE_1_0.txt) | |
6 | |
7 /** @file nonblocking.hpp | |
8 * | |
9 * This header defines operations for completing non-blocking | |
10 * communication requests. | |
11 */ | |
12 #ifndef BOOST_MPI_NONBLOCKING_HPP | |
13 #define BOOST_MPI_NONBLOCKING_HPP | |
14 | |
15 #include <boost/mpi/config.hpp> | |
16 #include <vector> | |
17 #include <iterator> // for std::iterator_traits | |
18 #include <boost/optional.hpp> | |
19 #include <utility> // for std::pair | |
20 #include <algorithm> // for iter_swap, reverse | |
21 #include <boost/static_assert.hpp> | |
22 #include <boost/mpi/request.hpp> | |
23 #include <boost/mpi/status.hpp> | |
24 #include <boost/mpi/exception.hpp> | |
25 | |
26 namespace boost { namespace mpi { | |
27 | |
28 /** | |
29 * @brief Wait until any non-blocking request has completed. | |
30 * | |
31 * This routine takes in a set of requests stored in the iterator | |
32 * range @c [first,last) and waits until any of these requests has | |
33 * been completed. It provides functionality equivalent to | |
34 * @c MPI_Waitany. | |
35 * | |
36 * @param first The iterator that denotes the beginning of the | |
37 * sequence of request objects. | |
38 * | |
39 * @param last The iterator that denotes the end of the sequence of | |
40 * request objects. This may not be equal to @c first. | |
41 * | |
42 * @returns A pair containing the status object that corresponds to | |
43 * the completed operation and the iterator referencing the completed | |
44 * request. | |
45 */ | |
46 template<typename ForwardIterator> | |
47 std::pair<status, ForwardIterator> | |
48 wait_any(ForwardIterator first, ForwardIterator last) | |
49 { | |
50 using std::advance; | |
51 | |
52 BOOST_ASSERT(first != last); | |
53 | |
54 typedef typename std::iterator_traits<ForwardIterator>::difference_type | |
55 difference_type; | |
56 | |
57 bool all_trivial_requests = true; | |
58 difference_type n = 0; | |
59 ForwardIterator current = first; | |
60 while (true) { | |
61 // Check if we have found a completed request. If so, return it. | |
62 if (optional<status> result = current->test()) | |
63 return std::make_pair(*result, current); | |
64 | |
65 // Check if this request (and all others before it) are "trivial" | |
66 // requests, e.g., they can be represented with a single | |
67 // MPI_Request. | |
68 all_trivial_requests = | |
69 all_trivial_requests | |
70 && !current->m_handler | |
71 && current->m_requests[1] == MPI_REQUEST_NULL; | |
72 | |
73 // Move to the next request. | |
74 ++n; | |
75 if (++current == last) { | |
76 // We have reached the end of the list. If all requests thus far | |
77 // have been trivial, we can call MPI_Waitany directly, because | |
78 // it may be more efficient than our busy-wait semantics. | |
79 if (all_trivial_requests) { | |
80 std::vector<MPI_Request> requests; | |
81 requests.reserve(n); | |
82 for (current = first; current != last; ++current) | |
83 requests.push_back(current->m_requests[0]); | |
84 | |
85 // Let MPI wait until one of these operations completes. | |
86 int index; | |
87 status stat; | |
88 BOOST_MPI_CHECK_RESULT(MPI_Waitany, | |
89 (n, &requests[0], &index, &stat.m_status)); | |
90 | |
91 // We don't have a notion of empty requests or status objects, | |
92 // so this is an error. | |
93 if (index == MPI_UNDEFINED) | |
94 boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST)); | |
95 | |
96 // Find the iterator corresponding to the completed request. | |
97 current = first; | |
98 advance(current, index); | |
99 current->m_requests[0] = requests[index]; | |
100 return std::make_pair(stat, current); | |
101 } | |
102 | |
103 // There are some nontrivial requests, so we must continue our | |
104 // busy waiting loop. | |
105 n = 0; | |
106 current = first; | |
107 all_trivial_requests = true; | |
108 } | |
109 } | |
110 | |
111 // We cannot ever get here | |
112 BOOST_ASSERT(false); | |
113 } | |
114 | |
115 /** | |
116 * @brief Test whether any non-blocking request has completed. | |
117 * | |
118 * This routine takes in a set of requests stored in the iterator | |
119 * range @c [first,last) and tests whether any of these requests has | |
120 * been completed. This routine is similar to @c wait_any, but will | |
121 * not block waiting for requests to completed. It provides | |
122 * functionality equivalent to @c MPI_Testany. | |
123 * | |
124 * @param first The iterator that denotes the beginning of the | |
125 * sequence of request objects. | |
126 * | |
127 * @param last The iterator that denotes the end of the sequence of | |
128 * request objects. | |
129 * | |
130 * @returns If any outstanding requests have completed, a pair | |
131 * containing the status object that corresponds to the completed | |
132 * operation and the iterator referencing the completed | |
133 * request. Otherwise, an empty @c optional<>. | |
134 */ | |
135 template<typename ForwardIterator> | |
136 optional<std::pair<status, ForwardIterator> > | |
137 test_any(ForwardIterator first, ForwardIterator last) | |
138 { | |
139 for (ForwardIterator current = first; first != last; ++first) { | |
140 // Check if we have found a completed request. If so, return it. | |
141 if (optional<status> result = current->test()) | |
142 return std::make_pair(*result, current); | |
143 } | |
144 | |
145 // We found nothing | |
146 return optional<std::pair<status, ForwardIterator> >(); | |
147 } | |
148 | |
149 /** | |
150 * @brief Wait until all non-blocking requests have completed. | |
151 * | |
152 * This routine takes in a set of requests stored in the iterator | |
153 * range @c [first,last) and waits until all of these requests have | |
154 * been completed. It provides functionality equivalent to | |
155 * @c MPI_Waitall. | |
156 * | |
157 * @param first The iterator that denotes the beginning of the | |
158 * sequence of request objects. | |
159 * | |
160 * @param last The iterator that denotes the end of the sequence of | |
161 * request objects. | |
162 * | |
163 * @param out If provided, an output iterator through which the | |
164 * status of each request will be emitted. The @c status objects are | |
165 * emitted in the same order as the requests are retrieved from | |
166 * @c [first,last). | |
167 * | |
168 * @returns If an @p out parameter was provided, the value @c out | |
169 * after all of the @c status objects have been emitted. | |
170 */ | |
171 template<typename ForwardIterator, typename OutputIterator> | |
172 OutputIterator | |
173 wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out) | |
174 { | |
175 typedef typename std::iterator_traits<ForwardIterator>::difference_type | |
176 difference_type; | |
177 | |
178 using std::distance; | |
179 | |
180 difference_type num_outstanding_requests = distance(first, last); | |
181 | |
182 std::vector<status> results(num_outstanding_requests); | |
183 std::vector<bool> completed(num_outstanding_requests); | |
184 | |
185 while (num_outstanding_requests > 0) { | |
186 bool all_trivial_requests = true; | |
187 difference_type idx = 0; | |
188 for (ForwardIterator current = first; current != last; ++current, ++idx) { | |
189 if (!completed[idx]) { | |
190 if (optional<status> stat = current->test()) { | |
191 // This outstanding request has been completed. We're done. | |
192 results[idx] = *stat; | |
193 completed[idx] = true; | |
194 --num_outstanding_requests; | |
195 all_trivial_requests = false; | |
196 } else { | |
197 // Check if this request (and all others before it) are "trivial" | |
198 // requests, e.g., they can be represented with a single | |
199 // MPI_Request. | |
200 all_trivial_requests = | |
201 all_trivial_requests | |
202 && !current->m_handler | |
203 && current->m_requests[1] == MPI_REQUEST_NULL; | |
204 } | |
205 } | |
206 } | |
207 | |
208 // If we have yet to fulfill any requests and all of the requests | |
209 // are trivial (i.e., require only a single MPI_Request to be | |
210 // fulfilled), call MPI_Waitall directly. | |
211 if (all_trivial_requests | |
212 && num_outstanding_requests == (difference_type)results.size()) { | |
213 std::vector<MPI_Request> requests; | |
214 requests.reserve(num_outstanding_requests); | |
215 for (ForwardIterator current = first; current != last; ++current) | |
216 requests.push_back(current->m_requests[0]); | |
217 | |
218 // Let MPI wait until all of these operations completes. | |
219 std::vector<MPI_Status> stats(num_outstanding_requests); | |
220 BOOST_MPI_CHECK_RESULT(MPI_Waitall, | |
221 (num_outstanding_requests, &requests[0], | |
222 &stats[0])); | |
223 | |
224 for (std::vector<MPI_Status>::iterator i = stats.begin(); | |
225 i != stats.end(); ++i, ++out) { | |
226 status stat; | |
227 stat.m_status = *i; | |
228 *out = stat; | |
229 } | |
230 | |
231 return out; | |
232 } | |
233 | |
234 all_trivial_requests = false; | |
235 } | |
236 | |
237 return std::copy(results.begin(), results.end(), out); | |
238 } | |
239 | |
240 /** | |
241 * \overload | |
242 */ | |
243 template<typename ForwardIterator> | |
244 void | |
245 wait_all(ForwardIterator first, ForwardIterator last) | |
246 { | |
247 typedef typename std::iterator_traits<ForwardIterator>::difference_type | |
248 difference_type; | |
249 | |
250 using std::distance; | |
251 | |
252 difference_type num_outstanding_requests = distance(first, last); | |
253 | |
254 std::vector<bool> completed(num_outstanding_requests); | |
255 | |
256 while (num_outstanding_requests > 0) { | |
257 bool all_trivial_requests = true; | |
258 | |
259 difference_type idx = 0; | |
260 for (ForwardIterator current = first; current != last; ++current, ++idx) { | |
261 if (!completed[idx]) { | |
262 if (optional<status> stat = current->test()) { | |
263 // This outstanding request has been completed. | |
264 completed[idx] = true; | |
265 --num_outstanding_requests; | |
266 all_trivial_requests = false; | |
267 } else { | |
268 // Check if this request (and all others before it) are "trivial" | |
269 // requests, e.g., they can be represented with a single | |
270 // MPI_Request. | |
271 all_trivial_requests = | |
272 all_trivial_requests | |
273 && !current->m_handler | |
274 && current->m_requests[1] == MPI_REQUEST_NULL; | |
275 } | |
276 } | |
277 } | |
278 | |
279 // If we have yet to fulfill any requests and all of the requests | |
280 // are trivial (i.e., require only a single MPI_Request to be | |
281 // fulfilled), call MPI_Waitall directly. | |
282 if (all_trivial_requests | |
283 && num_outstanding_requests == (difference_type)completed.size()) { | |
284 std::vector<MPI_Request> requests; | |
285 requests.reserve(num_outstanding_requests); | |
286 for (ForwardIterator current = first; current != last; ++current) | |
287 requests.push_back(current->m_requests[0]); | |
288 | |
289 // Let MPI wait until all of these operations completes. | |
290 BOOST_MPI_CHECK_RESULT(MPI_Waitall, | |
291 (num_outstanding_requests, &requests[0], | |
292 MPI_STATUSES_IGNORE)); | |
293 | |
294 // Signal completion | |
295 num_outstanding_requests = 0; | |
296 } | |
297 } | |
298 } | |
299 | |
300 /** | |
301 * @brief Tests whether all non-blocking requests have completed. | |
302 * | |
303 * This routine takes in a set of requests stored in the iterator | |
304 * range @c [first,last) and determines whether all of these requests | |
305 * have been completed. However, due to limitations of the underlying | |
306 * MPI implementation, if any of the requests refers to a | |
307 * non-blocking send or receive of a serialized data type, @c | |
308 * test_all will always return the equivalent of @c false (i.e., the | |
309 * requests cannot all be finished at this time). This routine | |
310 * performs the same functionality as @c wait_all, except that this | |
311 * routine will not block. This routine provides functionality | |
312 * equivalent to @c MPI_Testall. | |
313 * | |
314 * @param first The iterator that denotes the beginning of the | |
315 * sequence of request objects. | |
316 * | |
317 * @param last The iterator that denotes the end of the sequence of | |
318 * request objects. | |
319 * | |
320 * @param out If provided and all requests hav been completed, an | |
321 * output iterator through which the status of each request will be | |
322 * emitted. The @c status objects are emitted in the same order as | |
323 * the requests are retrieved from @c [first,last). | |
324 * | |
325 * @returns If an @p out parameter was provided, the value @c out | |
326 * after all of the @c status objects have been emitted (if all | |
327 * requests were completed) or an empty @c optional<>. If no @p out | |
328 * parameter was provided, returns @c true if all requests have | |
329 * completed or @c false otherwise. | |
330 */ | |
331 template<typename ForwardIterator, typename OutputIterator> | |
332 optional<OutputIterator> | |
333 test_all(ForwardIterator first, ForwardIterator last, OutputIterator out) | |
334 { | |
335 std::vector<MPI_Request> requests; | |
336 for (; first != last; ++first) { | |
337 // If we have a non-trivial request, then no requests can be | |
338 // completed. | |
339 if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL) | |
340 return optional<OutputIterator>(); | |
341 | |
342 requests.push_back(first->m_requests[0]); | |
343 } | |
344 | |
345 int flag = 0; | |
346 int n = requests.size(); | |
347 std::vector<MPI_Status> stats(n); | |
348 BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, &requests[0], &flag, &stats[0])); | |
349 if (flag) { | |
350 for (int i = 0; i < n; ++i, ++out) { | |
351 status stat; | |
352 stat.m_status = stats[i]; | |
353 *out = stat; | |
354 } | |
355 return out; | |
356 } else { | |
357 return optional<OutputIterator>(); | |
358 } | |
359 } | |
360 | |
361 /** | |
362 * \overload | |
363 */ | |
364 template<typename ForwardIterator> | |
365 bool | |
366 test_all(ForwardIterator first, ForwardIterator last) | |
367 { | |
368 std::vector<MPI_Request> requests; | |
369 for (; first != last; ++first) { | |
370 // If we have a non-trivial request, then no requests can be | |
371 // completed. | |
372 if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL) | |
373 return false; | |
374 | |
375 requests.push_back(first->m_requests[0]); | |
376 } | |
377 | |
378 int flag = 0; | |
379 int n = requests.size(); | |
380 BOOST_MPI_CHECK_RESULT(MPI_Testall, | |
381 (n, &requests[0], &flag, MPI_STATUSES_IGNORE)); | |
382 return flag != 0; | |
383 } | |
384 | |
385 /** | |
386 * @brief Wait until some non-blocking requests have completed. | |
387 * | |
388 * This routine takes in a set of requests stored in the iterator | |
389 * range @c [first,last) and waits until at least one of the requests | |
390 * has completed. It then completes all of the requests it can, | |
391 * partitioning the input sequence into pending requests followed by | |
392 * completed requests. If an output iterator is provided, @c status | |
393 * objects will be emitted for each of the completed requests. This | |
394 * routine provides functionality equivalent to @c MPI_Waitsome. | |
395 * | |
396 * @param first The iterator that denotes the beginning of the | |
397 * sequence of request objects. | |
398 * | |
399 * @param last The iterator that denotes the end of the sequence of | |
400 * request objects. This may not be equal to @c first. | |
401 * | |
402 * @param out If provided, the @c status objects corresponding to | |
403 * completed requests will be emitted through this output iterator. | |
404 | |
405 * @returns If the @p out parameter was provided, a pair containing | |
406 * the output iterator @p out after all of the @c status objects have | |
407 * been written through it and an iterator referencing the first | |
408 * completed request. If no @p out parameter was provided, only the | |
409 * iterator referencing the first completed request will be emitted. | |
410 */ | |
411 template<typename BidirectionalIterator, typename OutputIterator> | |
412 std::pair<OutputIterator, BidirectionalIterator> | |
413 wait_some(BidirectionalIterator first, BidirectionalIterator last, | |
414 OutputIterator out) | |
415 { | |
416 using std::advance; | |
417 | |
418 if (first == last) | |
419 return std::make_pair(out, first); | |
420 | |
421 typedef typename std::iterator_traits<BidirectionalIterator>::difference_type | |
422 difference_type; | |
423 | |
424 bool all_trivial_requests = true; | |
425 difference_type n = 0; | |
426 BidirectionalIterator current = first; | |
427 BidirectionalIterator start_of_completed = last; | |
428 while (true) { | |
429 // Check if we have found a completed request. | |
430 if (optional<status> result = current->test()) { | |
431 using std::iter_swap; | |
432 | |
433 // Emit the resulting status object | |
434 *out++ = *result; | |
435 | |
436 // We're expanding the set of completed requests | |
437 --start_of_completed; | |
438 | |
439 if (current == start_of_completed) { | |
440 // If we have hit the end of the list of pending | |
441 // requests. Finish up by fixing the order of the completed | |
442 // set to match the order in which we emitted status objects, | |
443 // then return. | |
444 std::reverse(start_of_completed, last); | |
445 return std::make_pair(out, start_of_completed); | |
446 } | |
447 | |
448 // Swap the request we just completed with the last request that | |
449 // has not yet been tested. | |
450 iter_swap(current, start_of_completed); | |
451 | |
452 continue; | |
453 } | |
454 | |
455 // Check if this request (and all others before it) are "trivial" | |
456 // requests, e.g., they can be represented with a single | |
457 // MPI_Request. | |
458 all_trivial_requests = | |
459 all_trivial_requests | |
460 && !current->m_handler | |
461 && current->m_requests[1] == MPI_REQUEST_NULL; | |
462 | |
463 // Move to the next request. | |
464 ++n; | |
465 if (++current == start_of_completed) { | |
466 if (start_of_completed != last) { | |
467 // We have satisfied some requests. Make the order of the | |
468 // completed requests match that of the status objects we've | |
469 // already emitted and we're done. | |
470 std::reverse(start_of_completed, last); | |
471 return std::make_pair(out, start_of_completed); | |
472 } | |
473 | |
474 // We have reached the end of the list. If all requests thus far | |
475 // have been trivial, we can call MPI_Waitsome directly, because | |
476 // it may be more efficient than our busy-wait semantics. | |
477 if (all_trivial_requests) { | |
478 std::vector<MPI_Request> requests; | |
479 std::vector<int> indices(n); | |
480 std::vector<MPI_Status> stats(n); | |
481 requests.reserve(n); | |
482 for (current = first; current != last; ++current) | |
483 requests.push_back(current->m_requests[0]); | |
484 | |
485 // Let MPI wait until some of these operations complete. | |
486 int num_completed; | |
487 BOOST_MPI_CHECK_RESULT(MPI_Waitsome, | |
488 (n, &requests[0], &num_completed, &indices[0], | |
489 &stats[0])); | |
490 | |
491 // Translate the index-based result of MPI_Waitsome into a | |
492 // partitioning on the requests. | |
493 int current_offset = 0; | |
494 current = first; | |
495 for (int index = 0; index < num_completed; ++index, ++out) { | |
496 using std::iter_swap; | |
497 | |
498 // Move "current" to the request object at this index | |
499 advance(current, indices[index] - current_offset); | |
500 current_offset = indices[index]; | |
501 | |
502 // Emit the status object | |
503 status stat; | |
504 stat.m_status = stats[index]; | |
505 *out = stat; | |
506 | |
507 // Finish up the request and swap it into the "completed | |
508 // requests" partition. | |
509 current->m_requests[0] = requests[indices[index]]; | |
510 --start_of_completed; | |
511 iter_swap(current, start_of_completed); | |
512 } | |
513 | |
514 // We have satisfied some requests. Make the order of the | |
515 // completed requests match that of the status objects we've | |
516 // already emitted and we're done. | |
517 std::reverse(start_of_completed, last); | |
518 return std::make_pair(out, start_of_completed); | |
519 } | |
520 | |
521 // There are some nontrivial requests, so we must continue our | |
522 // busy waiting loop. | |
523 n = 0; | |
524 current = first; | |
525 } | |
526 } | |
527 | |
528 // We cannot ever get here | |
529 BOOST_ASSERT(false); | |
530 } | |
531 | |
532 /** | |
533 * \overload | |
534 */ | |
535 template<typename BidirectionalIterator> | |
536 BidirectionalIterator | |
537 wait_some(BidirectionalIterator first, BidirectionalIterator last) | |
538 { | |
539 using std::advance; | |
540 | |
541 if (first == last) | |
542 return first; | |
543 | |
544 typedef typename std::iterator_traits<BidirectionalIterator>::difference_type | |
545 difference_type; | |
546 | |
547 bool all_trivial_requests = true; | |
548 difference_type n = 0; | |
549 BidirectionalIterator current = first; | |
550 BidirectionalIterator start_of_completed = last; | |
551 while (true) { | |
552 // Check if we have found a completed request. | |
553 if (optional<status> result = current->test()) { | |
554 using std::iter_swap; | |
555 | |
556 // We're expanding the set of completed requests | |
557 --start_of_completed; | |
558 | |
559 // If we have hit the end of the list of pending requests, we're | |
560 // done. | |
561 if (current == start_of_completed) | |
562 return start_of_completed; | |
563 | |
564 // Swap the request we just completed with the last request that | |
565 // has not yet been tested. | |
566 iter_swap(current, start_of_completed); | |
567 | |
568 continue; | |
569 } | |
570 | |
571 // Check if this request (and all others before it) are "trivial" | |
572 // requests, e.g., they can be represented with a single | |
573 // MPI_Request. | |
574 all_trivial_requests = | |
575 all_trivial_requests | |
576 && !current->m_handler | |
577 && current->m_requests[1] == MPI_REQUEST_NULL; | |
578 | |
579 // Move to the next request. | |
580 ++n; | |
581 if (++current == start_of_completed) { | |
582 // If we have satisfied some requests, we're done. | |
583 if (start_of_completed != last) | |
584 return start_of_completed; | |
585 | |
586 // We have reached the end of the list. If all requests thus far | |
587 // have been trivial, we can call MPI_Waitsome directly, because | |
588 // it may be more efficient than our busy-wait semantics. | |
589 if (all_trivial_requests) { | |
590 std::vector<MPI_Request> requests; | |
591 std::vector<int> indices(n); | |
592 requests.reserve(n); | |
593 for (current = first; current != last; ++current) | |
594 requests.push_back(current->m_requests[0]); | |
595 | |
596 // Let MPI wait until some of these operations complete. | |
597 int num_completed; | |
598 BOOST_MPI_CHECK_RESULT(MPI_Waitsome, | |
599 (n, &requests[0], &num_completed, &indices[0], | |
600 MPI_STATUSES_IGNORE)); | |
601 | |
602 // Translate the index-based result of MPI_Waitsome into a | |
603 // partitioning on the requests. | |
604 int current_offset = 0; | |
605 current = first; | |
606 for (int index = 0; index < num_completed; ++index) { | |
607 using std::iter_swap; | |
608 | |
609 // Move "current" to the request object at this index | |
610 advance(current, indices[index] - current_offset); | |
611 current_offset = indices[index]; | |
612 | |
613 // Finish up the request and swap it into the "completed | |
614 // requests" partition. | |
615 current->m_requests[0] = requests[indices[index]]; | |
616 --start_of_completed; | |
617 iter_swap(current, start_of_completed); | |
618 } | |
619 | |
620 // We have satisfied some requests, so we are done. | |
621 return start_of_completed; | |
622 } | |
623 | |
624 // There are some nontrivial requests, so we must continue our | |
625 // busy waiting loop. | |
626 n = 0; | |
627 current = first; | |
628 } | |
629 } | |
630 | |
631 // We cannot ever get here | |
632 BOOST_ASSERT(false); | |
633 } | |
634 | |
635 /** | |
636 * @brief Test whether some non-blocking requests have completed. | |
637 * | |
638 * This routine takes in a set of requests stored in the iterator | |
639 * range @c [first,last) and tests to see if any of the requests has | |
640 * completed. It completes all of the requests it can, partitioning | |
641 * the input sequence into pending requests followed by completed | |
642 * requests. If an output iterator is provided, @c status objects | |
643 * will be emitted for each of the completed requests. This routine | |
644 * is similar to @c wait_some, but does not wait until any requests | |
645 * have completed. This routine provides functionality equivalent to | |
646 * @c MPI_Testsome. | |
647 * | |
648 * @param first The iterator that denotes the beginning of the | |
649 * sequence of request objects. | |
650 * | |
651 * @param last The iterator that denotes the end of the sequence of | |
652 * request objects. This may not be equal to @c first. | |
653 * | |
654 * @param out If provided, the @c status objects corresponding to | |
655 * completed requests will be emitted through this output iterator. | |
656 | |
657 * @returns If the @p out parameter was provided, a pair containing | |
658 * the output iterator @p out after all of the @c status objects have | |
659 * been written through it and an iterator referencing the first | |
660 * completed request. If no @p out parameter was provided, only the | |
661 * iterator referencing the first completed request will be emitted. | |
662 */ | |
663 template<typename BidirectionalIterator, typename OutputIterator> | |
664 std::pair<OutputIterator, BidirectionalIterator> | |
665 test_some(BidirectionalIterator first, BidirectionalIterator last, | |
666 OutputIterator out) | |
667 { | |
668 BidirectionalIterator current = first; | |
669 BidirectionalIterator start_of_completed = last; | |
670 while (current != start_of_completed) { | |
671 // Check if we have found a completed request. | |
672 if (optional<status> result = current->test()) { | |
673 using std::iter_swap; | |
674 | |
675 // Emit the resulting status object | |
676 *out++ = *result; | |
677 | |
678 // We're expanding the set of completed requests | |
679 --start_of_completed; | |
680 | |
681 // Swap the request we just completed with the last request that | |
682 // has not yet been tested. | |
683 iter_swap(current, start_of_completed); | |
684 | |
685 continue; | |
686 } | |
687 | |
688 // Move to the next request. | |
689 ++current; | |
690 } | |
691 | |
692 // Finish up by fixing the order of the completed set to match the | |
693 // order in which we emitted status objects, then return. | |
694 std::reverse(start_of_completed, last); | |
695 return std::make_pair(out, start_of_completed); | |
696 } | |
697 | |
698 /** | |
699 * \overload | |
700 */ | |
701 template<typename BidirectionalIterator> | |
702 BidirectionalIterator | |
703 test_some(BidirectionalIterator first, BidirectionalIterator last) | |
704 { | |
705 BidirectionalIterator current = first; | |
706 BidirectionalIterator start_of_completed = last; | |
707 while (current != start_of_completed) { | |
708 // Check if we have found a completed request. | |
709 if (optional<status> result = current->test()) { | |
710 using std::iter_swap; | |
711 | |
712 // We're expanding the set of completed requests | |
713 --start_of_completed; | |
714 | |
715 // Swap the request we just completed with the last request that | |
716 // has not yet been tested. | |
717 iter_swap(current, start_of_completed); | |
718 | |
719 continue; | |
720 } | |
721 | |
722 // Move to the next request. | |
723 ++current; | |
724 } | |
725 | |
726 return start_of_completed; | |
727 } | |
728 | |
729 } } // end namespace boost::mpi | |
730 | |
731 | |
732 #endif // BOOST_MPI_NONBLOCKING_HPP |