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