nonblocking.hpp 25 KB

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