/Src/Dependencies/Boost/boost/mpi/nonblocking.hpp

http://hadesmem.googlecode.com/ · C++ Header · 732 lines · 362 code · 97 blank · 273 comment · 100 complexity · 09819ee31535cead39776d1a63494348 MD5 · raw file

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