Chris@16: // Copyright (C) 2006 Douglas Gregor . Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software Chris@16: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: /** @file nonblocking.hpp Chris@16: * Chris@16: * This header defines operations for completing non-blocking Chris@16: * communication requests. Chris@16: */ Chris@16: #ifndef BOOST_MPI_NONBLOCKING_HPP Chris@16: #define BOOST_MPI_NONBLOCKING_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include // for std::iterator_traits Chris@16: #include Chris@16: #include // for std::pair Chris@16: #include // for iter_swap, reverse Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace mpi { Chris@16: Chris@16: /** Chris@16: * @brief Wait until any non-blocking request has completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and waits until any of these requests has Chris@16: * been completed. It provides functionality equivalent to Chris@16: * @c MPI_Waitany. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. This may not be equal to @c first. Chris@16: * Chris@16: * @returns A pair containing the status object that corresponds to Chris@16: * the completed operation and the iterator referencing the completed Chris@16: * request. Chris@16: */ Chris@16: template Chris@16: std::pair Chris@16: wait_any(ForwardIterator first, ForwardIterator last) Chris@16: { Chris@16: using std::advance; Chris@16: Chris@16: BOOST_ASSERT(first != last); Chris@16: Chris@16: typedef typename std::iterator_traits::difference_type Chris@16: difference_type; Chris@16: Chris@16: bool all_trivial_requests = true; Chris@16: difference_type n = 0; Chris@16: ForwardIterator current = first; Chris@16: while (true) { Chris@16: // Check if we have found a completed request. If so, return it. Chris@101: if (current->m_requests[0] != MPI_REQUEST_NULL && Chris@101: current->m_requests[1] != MPI_REQUEST_NULL) Chris@101: if (optional result = current->test()) Chris@101: return std::make_pair(*result, current); Chris@16: Chris@16: // Check if this request (and all others before it) are "trivial" Chris@16: // requests, e.g., they can be represented with a single Chris@16: // MPI_Request. Chris@16: all_trivial_requests = Chris@16: all_trivial_requests Chris@16: && !current->m_handler Chris@16: && current->m_requests[1] == MPI_REQUEST_NULL; Chris@16: Chris@16: // Move to the next request. Chris@16: ++n; Chris@16: if (++current == last) { Chris@16: // We have reached the end of the list. If all requests thus far Chris@16: // have been trivial, we can call MPI_Waitany directly, because Chris@16: // it may be more efficient than our busy-wait semantics. Chris@16: if (all_trivial_requests) { Chris@16: std::vector requests; Chris@16: requests.reserve(n); Chris@16: for (current = first; current != last; ++current) Chris@16: requests.push_back(current->m_requests[0]); Chris@16: Chris@16: // Let MPI wait until one of these operations completes. Chris@16: int index; Chris@16: status stat; Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Waitany, Chris@16: (n, &requests[0], &index, &stat.m_status)); Chris@16: Chris@16: // We don't have a notion of empty requests or status objects, Chris@16: // so this is an error. Chris@16: if (index == MPI_UNDEFINED) Chris@16: boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST)); Chris@16: Chris@16: // Find the iterator corresponding to the completed request. Chris@16: current = first; Chris@16: advance(current, index); Chris@16: current->m_requests[0] = requests[index]; Chris@16: return std::make_pair(stat, current); Chris@16: } Chris@16: Chris@16: // There are some nontrivial requests, so we must continue our Chris@16: // busy waiting loop. Chris@16: n = 0; Chris@16: current = first; Chris@16: all_trivial_requests = true; Chris@16: } Chris@16: } Chris@16: Chris@16: // We cannot ever get here Chris@16: BOOST_ASSERT(false); Chris@16: } Chris@16: Chris@16: /** Chris@16: * @brief Test whether any non-blocking request has completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and tests whether any of these requests has Chris@16: * been completed. This routine is similar to @c wait_any, but will Chris@16: * not block waiting for requests to completed. It provides Chris@16: * functionality equivalent to @c MPI_Testany. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. Chris@16: * Chris@16: * @returns If any outstanding requests have completed, a pair Chris@16: * containing the status object that corresponds to the completed Chris@16: * operation and the iterator referencing the completed Chris@16: * request. Otherwise, an empty @c optional<>. Chris@16: */ Chris@16: template Chris@16: optional > Chris@16: test_any(ForwardIterator first, ForwardIterator last) Chris@16: { Chris@16: for (ForwardIterator current = first; first != last; ++first) { Chris@16: // Check if we have found a completed request. If so, return it. Chris@16: if (optional result = current->test()) Chris@16: return std::make_pair(*result, current); Chris@16: } Chris@16: Chris@16: // We found nothing Chris@16: return optional >(); Chris@16: } Chris@16: Chris@16: /** Chris@16: * @brief Wait until all non-blocking requests have completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and waits until all of these requests have Chris@16: * been completed. It provides functionality equivalent to Chris@16: * @c MPI_Waitall. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. Chris@16: * Chris@16: * @param out If provided, an output iterator through which the Chris@16: * status of each request will be emitted. The @c status objects are Chris@16: * emitted in the same order as the requests are retrieved from Chris@16: * @c [first,last). Chris@16: * Chris@16: * @returns If an @p out parameter was provided, the value @c out Chris@16: * after all of the @c status objects have been emitted. Chris@16: */ Chris@16: template Chris@16: OutputIterator Chris@16: wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out) Chris@16: { Chris@16: typedef typename std::iterator_traits::difference_type Chris@16: difference_type; Chris@16: Chris@16: using std::distance; Chris@16: Chris@16: difference_type num_outstanding_requests = distance(first, last); Chris@16: Chris@16: std::vector results(num_outstanding_requests); Chris@16: std::vector completed(num_outstanding_requests); Chris@16: Chris@16: while (num_outstanding_requests > 0) { Chris@16: bool all_trivial_requests = true; Chris@16: difference_type idx = 0; Chris@16: for (ForwardIterator current = first; current != last; ++current, ++idx) { Chris@16: if (!completed[idx]) { Chris@16: if (optional stat = current->test()) { Chris@16: // This outstanding request has been completed. We're done. Chris@16: results[idx] = *stat; Chris@16: completed[idx] = true; Chris@16: --num_outstanding_requests; Chris@16: all_trivial_requests = false; Chris@16: } else { Chris@16: // Check if this request (and all others before it) are "trivial" Chris@16: // requests, e.g., they can be represented with a single Chris@16: // MPI_Request. Chris@16: all_trivial_requests = Chris@16: all_trivial_requests Chris@16: && !current->m_handler Chris@16: && current->m_requests[1] == MPI_REQUEST_NULL; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // If we have yet to fulfill any requests and all of the requests Chris@16: // are trivial (i.e., require only a single MPI_Request to be Chris@16: // fulfilled), call MPI_Waitall directly. Chris@16: if (all_trivial_requests Chris@16: && num_outstanding_requests == (difference_type)results.size()) { Chris@16: std::vector requests; Chris@16: requests.reserve(num_outstanding_requests); Chris@16: for (ForwardIterator current = first; current != last; ++current) Chris@16: requests.push_back(current->m_requests[0]); Chris@16: Chris@16: // Let MPI wait until all of these operations completes. Chris@16: std::vector stats(num_outstanding_requests); Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Waitall, Chris@16: (num_outstanding_requests, &requests[0], Chris@16: &stats[0])); Chris@16: Chris@16: for (std::vector::iterator i = stats.begin(); Chris@16: i != stats.end(); ++i, ++out) { Chris@16: status stat; Chris@16: stat.m_status = *i; Chris@16: *out = stat; Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: all_trivial_requests = false; Chris@16: } Chris@16: Chris@16: return std::copy(results.begin(), results.end(), out); Chris@16: } Chris@16: Chris@16: /** Chris@16: * \overload Chris@16: */ Chris@16: template Chris@16: void Chris@16: wait_all(ForwardIterator first, ForwardIterator last) Chris@16: { Chris@16: typedef typename std::iterator_traits::difference_type Chris@16: difference_type; Chris@16: Chris@16: using std::distance; Chris@16: Chris@16: difference_type num_outstanding_requests = distance(first, last); Chris@16: Chris@16: std::vector completed(num_outstanding_requests); Chris@16: Chris@16: while (num_outstanding_requests > 0) { Chris@16: bool all_trivial_requests = true; Chris@16: Chris@16: difference_type idx = 0; Chris@16: for (ForwardIterator current = first; current != last; ++current, ++idx) { Chris@16: if (!completed[idx]) { Chris@16: if (optional stat = current->test()) { Chris@16: // This outstanding request has been completed. Chris@16: completed[idx] = true; Chris@16: --num_outstanding_requests; Chris@16: all_trivial_requests = false; Chris@16: } else { Chris@16: // Check if this request (and all others before it) are "trivial" Chris@16: // requests, e.g., they can be represented with a single Chris@16: // MPI_Request. Chris@16: all_trivial_requests = Chris@16: all_trivial_requests Chris@16: && !current->m_handler Chris@16: && current->m_requests[1] == MPI_REQUEST_NULL; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: // If we have yet to fulfill any requests and all of the requests Chris@16: // are trivial (i.e., require only a single MPI_Request to be Chris@16: // fulfilled), call MPI_Waitall directly. Chris@16: if (all_trivial_requests Chris@16: && num_outstanding_requests == (difference_type)completed.size()) { Chris@16: std::vector requests; Chris@16: requests.reserve(num_outstanding_requests); Chris@16: for (ForwardIterator current = first; current != last; ++current) Chris@16: requests.push_back(current->m_requests[0]); Chris@16: Chris@16: // Let MPI wait until all of these operations completes. Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Waitall, Chris@16: (num_outstanding_requests, &requests[0], Chris@16: MPI_STATUSES_IGNORE)); Chris@16: Chris@16: // Signal completion Chris@16: num_outstanding_requests = 0; Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: /** Chris@16: * @brief Tests whether all non-blocking requests have completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and determines whether all of these requests Chris@16: * have been completed. However, due to limitations of the underlying Chris@16: * MPI implementation, if any of the requests refers to a Chris@16: * non-blocking send or receive of a serialized data type, @c Chris@16: * test_all will always return the equivalent of @c false (i.e., the Chris@16: * requests cannot all be finished at this time). This routine Chris@16: * performs the same functionality as @c wait_all, except that this Chris@16: * routine will not block. This routine provides functionality Chris@16: * equivalent to @c MPI_Testall. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. Chris@16: * Chris@16: * @param out If provided and all requests hav been completed, an Chris@16: * output iterator through which the status of each request will be Chris@16: * emitted. The @c status objects are emitted in the same order as Chris@16: * the requests are retrieved from @c [first,last). Chris@16: * Chris@16: * @returns If an @p out parameter was provided, the value @c out Chris@16: * after all of the @c status objects have been emitted (if all Chris@16: * requests were completed) or an empty @c optional<>. If no @p out Chris@16: * parameter was provided, returns @c true if all requests have Chris@16: * completed or @c false otherwise. Chris@16: */ Chris@16: template Chris@16: optional Chris@16: test_all(ForwardIterator first, ForwardIterator last, OutputIterator out) Chris@16: { Chris@16: std::vector requests; Chris@16: for (; first != last; ++first) { Chris@16: // If we have a non-trivial request, then no requests can be Chris@16: // completed. Chris@16: if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL) Chris@16: return optional(); Chris@16: Chris@16: requests.push_back(first->m_requests[0]); Chris@16: } Chris@16: Chris@16: int flag = 0; Chris@16: int n = requests.size(); Chris@16: std::vector stats(n); Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, &requests[0], &flag, &stats[0])); Chris@16: if (flag) { Chris@16: for (int i = 0; i < n; ++i, ++out) { Chris@16: status stat; Chris@16: stat.m_status = stats[i]; Chris@16: *out = stat; Chris@16: } Chris@16: return out; Chris@16: } else { Chris@16: return optional(); Chris@16: } Chris@16: } Chris@16: Chris@16: /** Chris@16: * \overload Chris@16: */ Chris@16: template Chris@16: bool Chris@16: test_all(ForwardIterator first, ForwardIterator last) Chris@16: { Chris@16: std::vector requests; Chris@16: for (; first != last; ++first) { Chris@16: // If we have a non-trivial request, then no requests can be Chris@16: // completed. Chris@16: if (first->m_handler || first->m_requests[1] != MPI_REQUEST_NULL) Chris@16: return false; Chris@16: Chris@16: requests.push_back(first->m_requests[0]); Chris@16: } Chris@16: Chris@16: int flag = 0; Chris@16: int n = requests.size(); Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Testall, Chris@16: (n, &requests[0], &flag, MPI_STATUSES_IGNORE)); Chris@16: return flag != 0; Chris@16: } Chris@16: Chris@16: /** Chris@16: * @brief Wait until some non-blocking requests have completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and waits until at least one of the requests Chris@16: * has completed. It then completes all of the requests it can, Chris@16: * partitioning the input sequence into pending requests followed by Chris@16: * completed requests. If an output iterator is provided, @c status Chris@16: * objects will be emitted for each of the completed requests. This Chris@16: * routine provides functionality equivalent to @c MPI_Waitsome. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. This may not be equal to @c first. Chris@16: * Chris@16: * @param out If provided, the @c status objects corresponding to Chris@16: * completed requests will be emitted through this output iterator. Chris@16: Chris@16: * @returns If the @p out parameter was provided, a pair containing Chris@16: * the output iterator @p out after all of the @c status objects have Chris@16: * been written through it and an iterator referencing the first Chris@16: * completed request. If no @p out parameter was provided, only the Chris@16: * iterator referencing the first completed request will be emitted. Chris@16: */ Chris@16: template Chris@16: std::pair Chris@16: wait_some(BidirectionalIterator first, BidirectionalIterator last, Chris@16: OutputIterator out) Chris@16: { Chris@16: using std::advance; Chris@16: Chris@16: if (first == last) Chris@16: return std::make_pair(out, first); Chris@16: Chris@16: typedef typename std::iterator_traits::difference_type Chris@16: difference_type; Chris@16: Chris@16: bool all_trivial_requests = true; Chris@16: difference_type n = 0; Chris@16: BidirectionalIterator current = first; Chris@16: BidirectionalIterator start_of_completed = last; Chris@16: while (true) { Chris@16: // Check if we have found a completed request. Chris@16: if (optional result = current->test()) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // Emit the resulting status object Chris@16: *out++ = *result; Chris@16: Chris@16: // We're expanding the set of completed requests Chris@16: --start_of_completed; Chris@16: Chris@16: if (current == start_of_completed) { Chris@16: // If we have hit the end of the list of pending Chris@16: // requests. Finish up by fixing the order of the completed Chris@16: // set to match the order in which we emitted status objects, Chris@16: // then return. Chris@16: std::reverse(start_of_completed, last); Chris@16: return std::make_pair(out, start_of_completed); Chris@16: } Chris@16: Chris@16: // Swap the request we just completed with the last request that Chris@16: // has not yet been tested. Chris@16: iter_swap(current, start_of_completed); Chris@16: Chris@16: continue; Chris@16: } Chris@16: Chris@16: // Check if this request (and all others before it) are "trivial" Chris@16: // requests, e.g., they can be represented with a single Chris@16: // MPI_Request. Chris@16: all_trivial_requests = Chris@16: all_trivial_requests Chris@16: && !current->m_handler Chris@16: && current->m_requests[1] == MPI_REQUEST_NULL; Chris@16: Chris@16: // Move to the next request. Chris@16: ++n; Chris@16: if (++current == start_of_completed) { Chris@16: if (start_of_completed != last) { Chris@16: // We have satisfied some requests. Make the order of the Chris@16: // completed requests match that of the status objects we've Chris@16: // already emitted and we're done. Chris@16: std::reverse(start_of_completed, last); Chris@16: return std::make_pair(out, start_of_completed); Chris@16: } Chris@16: Chris@16: // We have reached the end of the list. If all requests thus far Chris@16: // have been trivial, we can call MPI_Waitsome directly, because Chris@16: // it may be more efficient than our busy-wait semantics. Chris@16: if (all_trivial_requests) { Chris@16: std::vector requests; Chris@16: std::vector indices(n); Chris@16: std::vector stats(n); Chris@16: requests.reserve(n); Chris@16: for (current = first; current != last; ++current) Chris@16: requests.push_back(current->m_requests[0]); Chris@16: Chris@16: // Let MPI wait until some of these operations complete. Chris@16: int num_completed; Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Waitsome, Chris@16: (n, &requests[0], &num_completed, &indices[0], Chris@16: &stats[0])); Chris@16: Chris@16: // Translate the index-based result of MPI_Waitsome into a Chris@16: // partitioning on the requests. Chris@16: int current_offset = 0; Chris@16: current = first; Chris@16: for (int index = 0; index < num_completed; ++index, ++out) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // Move "current" to the request object at this index Chris@16: advance(current, indices[index] - current_offset); Chris@16: current_offset = indices[index]; Chris@16: Chris@16: // Emit the status object Chris@16: status stat; Chris@16: stat.m_status = stats[index]; Chris@16: *out = stat; Chris@16: Chris@16: // Finish up the request and swap it into the "completed Chris@16: // requests" partition. Chris@16: current->m_requests[0] = requests[indices[index]]; Chris@16: --start_of_completed; Chris@16: iter_swap(current, start_of_completed); Chris@16: } Chris@16: Chris@16: // We have satisfied some requests. Make the order of the Chris@16: // completed requests match that of the status objects we've Chris@16: // already emitted and we're done. Chris@16: std::reverse(start_of_completed, last); Chris@16: return std::make_pair(out, start_of_completed); Chris@16: } Chris@16: Chris@16: // There are some nontrivial requests, so we must continue our Chris@16: // busy waiting loop. Chris@16: n = 0; Chris@16: current = first; Chris@16: } Chris@16: } Chris@16: Chris@16: // We cannot ever get here Chris@16: BOOST_ASSERT(false); Chris@16: } Chris@16: Chris@16: /** Chris@16: * \overload Chris@16: */ Chris@16: template Chris@16: BidirectionalIterator Chris@16: wait_some(BidirectionalIterator first, BidirectionalIterator last) Chris@16: { Chris@16: using std::advance; Chris@16: Chris@16: if (first == last) Chris@16: return first; Chris@16: Chris@16: typedef typename std::iterator_traits::difference_type Chris@16: difference_type; Chris@16: Chris@16: bool all_trivial_requests = true; Chris@16: difference_type n = 0; Chris@16: BidirectionalIterator current = first; Chris@16: BidirectionalIterator start_of_completed = last; Chris@16: while (true) { Chris@16: // Check if we have found a completed request. Chris@16: if (optional result = current->test()) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // We're expanding the set of completed requests Chris@16: --start_of_completed; Chris@16: Chris@16: // If we have hit the end of the list of pending requests, we're Chris@16: // done. Chris@16: if (current == start_of_completed) Chris@16: return start_of_completed; Chris@16: Chris@16: // Swap the request we just completed with the last request that Chris@16: // has not yet been tested. Chris@16: iter_swap(current, start_of_completed); Chris@16: Chris@16: continue; Chris@16: } Chris@16: Chris@16: // Check if this request (and all others before it) are "trivial" Chris@16: // requests, e.g., they can be represented with a single Chris@16: // MPI_Request. Chris@16: all_trivial_requests = Chris@16: all_trivial_requests Chris@16: && !current->m_handler Chris@16: && current->m_requests[1] == MPI_REQUEST_NULL; Chris@16: Chris@16: // Move to the next request. Chris@16: ++n; Chris@16: if (++current == start_of_completed) { Chris@16: // If we have satisfied some requests, we're done. Chris@16: if (start_of_completed != last) Chris@16: return start_of_completed; Chris@16: Chris@16: // We have reached the end of the list. If all requests thus far Chris@16: // have been trivial, we can call MPI_Waitsome directly, because Chris@16: // it may be more efficient than our busy-wait semantics. Chris@16: if (all_trivial_requests) { Chris@16: std::vector requests; Chris@16: std::vector indices(n); Chris@16: requests.reserve(n); Chris@16: for (current = first; current != last; ++current) Chris@16: requests.push_back(current->m_requests[0]); Chris@16: Chris@16: // Let MPI wait until some of these operations complete. Chris@16: int num_completed; Chris@16: BOOST_MPI_CHECK_RESULT(MPI_Waitsome, Chris@16: (n, &requests[0], &num_completed, &indices[0], Chris@16: MPI_STATUSES_IGNORE)); Chris@16: Chris@16: // Translate the index-based result of MPI_Waitsome into a Chris@16: // partitioning on the requests. Chris@16: int current_offset = 0; Chris@16: current = first; Chris@16: for (int index = 0; index < num_completed; ++index) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // Move "current" to the request object at this index Chris@16: advance(current, indices[index] - current_offset); Chris@16: current_offset = indices[index]; Chris@16: Chris@16: // Finish up the request and swap it into the "completed Chris@16: // requests" partition. Chris@16: current->m_requests[0] = requests[indices[index]]; Chris@16: --start_of_completed; Chris@16: iter_swap(current, start_of_completed); Chris@16: } Chris@16: Chris@16: // We have satisfied some requests, so we are done. Chris@16: return start_of_completed; Chris@16: } Chris@16: Chris@16: // There are some nontrivial requests, so we must continue our Chris@16: // busy waiting loop. Chris@16: n = 0; Chris@16: current = first; Chris@16: } Chris@16: } Chris@16: Chris@16: // We cannot ever get here Chris@16: BOOST_ASSERT(false); Chris@16: } Chris@16: Chris@16: /** Chris@16: * @brief Test whether some non-blocking requests have completed. Chris@16: * Chris@16: * This routine takes in a set of requests stored in the iterator Chris@16: * range @c [first,last) and tests to see if any of the requests has Chris@16: * completed. It completes all of the requests it can, partitioning Chris@16: * the input sequence into pending requests followed by completed Chris@16: * requests. If an output iterator is provided, @c status objects Chris@16: * will be emitted for each of the completed requests. This routine Chris@16: * is similar to @c wait_some, but does not wait until any requests Chris@16: * have completed. This routine provides functionality equivalent to Chris@16: * @c MPI_Testsome. Chris@16: * Chris@16: * @param first The iterator that denotes the beginning of the Chris@16: * sequence of request objects. Chris@16: * Chris@16: * @param last The iterator that denotes the end of the sequence of Chris@16: * request objects. This may not be equal to @c first. Chris@16: * Chris@16: * @param out If provided, the @c status objects corresponding to Chris@16: * completed requests will be emitted through this output iterator. Chris@16: Chris@16: * @returns If the @p out parameter was provided, a pair containing Chris@16: * the output iterator @p out after all of the @c status objects have Chris@16: * been written through it and an iterator referencing the first Chris@16: * completed request. If no @p out parameter was provided, only the Chris@16: * iterator referencing the first completed request will be emitted. Chris@16: */ Chris@16: template Chris@16: std::pair Chris@16: test_some(BidirectionalIterator first, BidirectionalIterator last, Chris@16: OutputIterator out) Chris@16: { Chris@16: BidirectionalIterator current = first; Chris@16: BidirectionalIterator start_of_completed = last; Chris@16: while (current != start_of_completed) { Chris@16: // Check if we have found a completed request. Chris@16: if (optional result = current->test()) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // Emit the resulting status object Chris@16: *out++ = *result; Chris@16: Chris@16: // We're expanding the set of completed requests Chris@16: --start_of_completed; Chris@16: Chris@16: // Swap the request we just completed with the last request that Chris@16: // has not yet been tested. Chris@16: iter_swap(current, start_of_completed); Chris@16: Chris@16: continue; Chris@16: } Chris@16: Chris@16: // Move to the next request. Chris@16: ++current; Chris@16: } Chris@16: Chris@16: // Finish up by fixing the order of the completed set to match the Chris@16: // order in which we emitted status objects, then return. Chris@16: std::reverse(start_of_completed, last); Chris@16: return std::make_pair(out, start_of_completed); Chris@16: } Chris@16: Chris@16: /** Chris@16: * \overload Chris@16: */ Chris@16: template Chris@16: BidirectionalIterator Chris@16: test_some(BidirectionalIterator first, BidirectionalIterator last) Chris@16: { Chris@16: BidirectionalIterator current = first; Chris@16: BidirectionalIterator start_of_completed = last; Chris@16: while (current != start_of_completed) { Chris@16: // Check if we have found a completed request. Chris@16: if (optional result = current->test()) { Chris@16: using std::iter_swap; Chris@16: Chris@16: // We're expanding the set of completed requests Chris@16: --start_of_completed; Chris@16: Chris@16: // Swap the request we just completed with the last request that Chris@16: // has not yet been tested. Chris@16: iter_swap(current, start_of_completed); Chris@16: Chris@16: continue; Chris@16: } Chris@16: Chris@16: // Move to the next request. Chris@16: ++current; Chris@16: } Chris@16: Chris@16: return start_of_completed; Chris@16: } Chris@16: Chris@16: } } // end namespace boost::mpi Chris@16: Chris@16: Chris@16: #endif // BOOST_MPI_NONBLOCKING_HPP