File indexing completed on 2025-10-31 08:45:01
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 
0010 
0011 
0012 #ifndef BOOST_MPI_NONBLOCKING_HPP
0013 #define BOOST_MPI_NONBLOCKING_HPP
0014 
0015 #include <boost/mpi/config.hpp>
0016 #include <vector>
0017 #include <iterator> // for std::iterator_traits
0018 #include <boost/optional.hpp>
0019 #include <utility> // for std::pair
0020 #include <algorithm> // for iter_swap, reverse
0021 #include <boost/static_assert.hpp>
0022 #include <boost/mpi/request.hpp>
0023 #include <boost/mpi/status.hpp>
0024 #include <boost/mpi/exception.hpp>
0025 
0026 namespace boost { namespace mpi {
0027 
0028 
0029 
0030 
0031 
0032 
0033 
0034 
0035 
0036 
0037 
0038 
0039 
0040 
0041 
0042 
0043 
0044 
0045 
0046 template<typename ForwardIterator>
0047 std::pair<status, ForwardIterator> 
0048 wait_any(ForwardIterator first, ForwardIterator last)
0049 {
0050   using std::advance;
0051 
0052   BOOST_ASSERT(first != last);
0053   
0054   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0055     difference_type;
0056 
0057   bool all_trivial_requests = true;
0058   difference_type n = 0;
0059   ForwardIterator current = first;
0060   while (true) {
0061     
0062     if (current->active()) {
0063       optional<status> result = current->test();
0064       if (bool(result)) {
0065         return std::make_pair(*result, current);
0066       }
0067     }
0068     
0069     
0070     
0071     
0072     
0073     
0074     
0075     all_trivial_requests = all_trivial_requests && current->trivial();
0076 
0077     
0078     ++n;
0079     if (++current == last) {
0080       
0081       
0082       
0083       if (all_trivial_requests) {
0084         std::vector<MPI_Request> requests;
0085         requests.reserve(n);
0086         for (current = first; current != last; ++current) {
0087           requests.push_back(*current->trivial());
0088         }
0089 
0090         
0091         int index;
0092         status stat;
0093         BOOST_MPI_CHECK_RESULT(MPI_Waitany, 
0094                                (n, detail::c_data(requests), &index, &stat.m_status));
0095 
0096         
0097         
0098         if (index == MPI_UNDEFINED)
0099           boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
0100 
0101         
0102         current = first;
0103         advance(current, index);
0104         *current->trivial() = requests[index];
0105         return std::make_pair(stat, current);
0106       }
0107 
0108       
0109       
0110       n = 0;
0111       current = first;
0112       all_trivial_requests = true;
0113     }
0114   }
0115 
0116   
0117   BOOST_ASSERT(false);
0118 }
0119 
0120 
0121 
0122 
0123 
0124 
0125 
0126 
0127 
0128 
0129 
0130 
0131 
0132 
0133 
0134 
0135 
0136 
0137 
0138 
0139 
0140 template<typename ForwardIterator>
0141 optional<std::pair<status, ForwardIterator> >
0142 test_any(ForwardIterator first, ForwardIterator last)
0143 {
0144   while (first != last) {
0145     
0146     if (optional<status> result = first->test()) {
0147       return std::make_pair(*result, first);
0148     }
0149     ++first;
0150   }
0151 
0152   
0153   return optional<std::pair<status, ForwardIterator> >();
0154 }
0155 
0156 
0157 
0158 
0159 
0160 
0161 
0162 
0163 
0164 
0165 
0166 
0167 
0168 
0169 
0170 
0171 
0172 
0173 
0174 
0175 
0176 
0177 
0178 template<typename ForwardIterator, typename OutputIterator>
0179 OutputIterator 
0180 wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0181 {
0182   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0183     difference_type;
0184 
0185   using std::distance;
0186 
0187   difference_type num_outstanding_requests = distance(first, last);
0188 
0189   std::vector<status> results(num_outstanding_requests);
0190   std::vector<bool> completed(num_outstanding_requests);
0191 
0192   while (num_outstanding_requests > 0) {
0193     bool all_trivial_requests = true;
0194     difference_type idx = 0;
0195     for (ForwardIterator current = first; current != last; ++current, ++idx) {
0196       if (!completed[idx]) {
0197         if (!current->active()) {
0198           completed[idx] = true;
0199           --num_outstanding_requests;
0200         } else if (optional<status> stat = current->test()) {
0201           
0202           results[idx] = *stat;
0203           completed[idx] = true;
0204           --num_outstanding_requests;
0205           all_trivial_requests = false;
0206         } else {
0207           
0208           
0209           
0210           all_trivial_requests = all_trivial_requests && current->trivial();
0211         }
0212       }
0213     }
0214 
0215     
0216     
0217     
0218     if (all_trivial_requests 
0219         && num_outstanding_requests == (difference_type)results.size()) {
0220       std::vector<MPI_Request> requests;
0221       requests.reserve(num_outstanding_requests);
0222       for (ForwardIterator current = first; current != last; ++current)
0223         requests.push_back(*current->trivial());
0224 
0225       
0226       std::vector<MPI_Status> stats(num_outstanding_requests);
0227       BOOST_MPI_CHECK_RESULT(MPI_Waitall, 
0228                              (num_outstanding_requests, detail::c_data(requests), 
0229                               detail::c_data(stats)));
0230 
0231       for (std::vector<MPI_Status>::iterator i = stats.begin(); 
0232            i != stats.end(); ++i, ++out) {
0233         status stat;
0234         stat.m_status = *i;
0235         *out = stat;
0236       }
0237 
0238       return out;
0239     }
0240 
0241     all_trivial_requests = false;
0242   }
0243 
0244   return std::copy(results.begin(), results.end(), out);
0245 }
0246 
0247 
0248 
0249 
0250 template<typename ForwardIterator>
0251 void
0252 wait_all(ForwardIterator first, ForwardIterator last)
0253 {
0254   typedef typename std::iterator_traits<ForwardIterator>::difference_type
0255     difference_type;
0256 
0257   using std::distance;
0258 
0259   difference_type num_outstanding_requests = distance(first, last);
0260 
0261   std::vector<bool> completed(num_outstanding_requests, false);
0262 
0263   while (num_outstanding_requests > 0) {
0264     bool all_trivial_requests = true;
0265 
0266     difference_type idx = 0;
0267     for (ForwardIterator current = first; current != last; ++current, ++idx) {
0268       if (!completed[idx]) {
0269         if (!current->active()) {
0270           completed[idx] = true;
0271           --num_outstanding_requests;
0272         } else if (optional<status> stat = current->test()) {
0273           
0274           completed[idx] = true;
0275           --num_outstanding_requests;
0276           all_trivial_requests = false;
0277         } else {
0278           
0279           
0280           
0281           all_trivial_requests = all_trivial_requests && current->trivial();
0282         }
0283       }
0284     }
0285 
0286     
0287     
0288     
0289     if (all_trivial_requests 
0290         && num_outstanding_requests == (difference_type)completed.size()) {
0291       std::vector<MPI_Request> requests;
0292       requests.reserve(num_outstanding_requests);
0293       for (ForwardIterator current = first; current != last; ++current)
0294         requests.push_back(*current->trivial());
0295 
0296       
0297       BOOST_MPI_CHECK_RESULT(MPI_Waitall, 
0298                              (num_outstanding_requests, detail::c_data(requests), 
0299                               MPI_STATUSES_IGNORE));
0300 
0301       
0302       num_outstanding_requests = 0;
0303     }
0304   }
0305 }
0306 
0307 
0308 
0309 
0310 
0311 
0312 
0313 
0314 
0315 
0316 
0317 
0318 
0319 
0320 
0321 
0322 
0323 
0324 
0325 
0326 
0327 
0328 
0329 
0330 
0331 
0332 
0333 
0334 
0335 
0336 
0337 
0338 template<typename ForwardIterator, typename OutputIterator>
0339 optional<OutputIterator>
0340 test_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0341 {
0342   std::vector<MPI_Request> requests;
0343   for (; first != last; ++first) {
0344     
0345     
0346     if (!first->trivial()) {
0347       return optional<OutputIterator>();
0348     }
0349     requests.push_back(*first->trivial());
0350   }
0351 
0352   int flag = 0;
0353   int n = requests.size();
0354   std::vector<MPI_Status> stats(n);
0355   BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, detail::c_data(requests), &flag, detail::c_data(stats)));
0356   if (flag) {
0357     for (int i = 0; i < n; ++i, ++out) {
0358       status stat;
0359       stat.m_status = stats[i];
0360       *out = stat;
0361     }
0362     return out;
0363   } else {
0364     return optional<OutputIterator>();
0365   }
0366 }
0367 
0368 
0369 
0370 
0371 template<typename ForwardIterator>
0372 bool
0373 test_all(ForwardIterator first, ForwardIterator last)
0374 {
0375   std::vector<MPI_Request> requests;
0376   for (; first != last; ++first) {
0377     
0378     
0379     if (!first->trivial()) {
0380       return false;
0381     }
0382     requests.push_back(*first->trivial());
0383   }
0384 
0385   int flag = 0;
0386   int n = requests.size();
0387   BOOST_MPI_CHECK_RESULT(MPI_Testall, 
0388                          (n, detail::c_data(requests), &flag, MPI_STATUSES_IGNORE));
0389   return flag != 0;
0390 }
0391 
0392 
0393 
0394 
0395 
0396 
0397 
0398 
0399 
0400 
0401 
0402 
0403 
0404 
0405 
0406 
0407 
0408 
0409 
0410 
0411 
0412 
0413 
0414 
0415 
0416 
0417 
0418 template<typename BidirectionalIterator, typename OutputIterator>
0419 std::pair<OutputIterator, BidirectionalIterator> 
0420 wait_some(BidirectionalIterator first, BidirectionalIterator last,
0421           OutputIterator out)
0422 {
0423   using std::advance;
0424 
0425   if (first == last)
0426     return std::make_pair(out, first);
0427   
0428   typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0429     difference_type;
0430 
0431   bool all_trivial_requests = true;
0432   difference_type n = 0;
0433   BidirectionalIterator current = first;
0434   BidirectionalIterator start_of_completed = last;
0435   while (true) {
0436     
0437     if (optional<status> result = current->test()) {
0438       using std::iter_swap;
0439 
0440       
0441       *out++ = *result;
0442 
0443       
0444       --start_of_completed;
0445 
0446       if (current == start_of_completed) {
0447         
0448         
0449         
0450         
0451         std::reverse(start_of_completed, last);
0452         return std::make_pair(out, start_of_completed);
0453       }
0454 
0455       
0456       
0457       iter_swap(current, start_of_completed);
0458 
0459       continue;
0460     }
0461 
0462     
0463     
0464     
0465     all_trivial_requests = all_trivial_requests && current->trivial();
0466 
0467     
0468     ++n;
0469     if (++current == start_of_completed) {
0470       if (start_of_completed != last) {
0471         
0472         
0473         
0474         std::reverse(start_of_completed, last);
0475         return std::make_pair(out, start_of_completed);
0476       }
0477 
0478       
0479       
0480       
0481       if (all_trivial_requests) {
0482         std::vector<MPI_Request> requests;
0483         std::vector<int> indices(n);
0484         std::vector<MPI_Status> stats(n);
0485         requests.reserve(n);
0486         for (current = first; current != last; ++current)
0487           requests.push_back(*current->trivial());
0488 
0489         
0490         int num_completed;
0491         BOOST_MPI_CHECK_RESULT(MPI_Waitsome, 
0492                                (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0493                                 detail::c_data(stats)));
0494 
0495         
0496         
0497         int current_offset = 0;
0498         current = first;
0499         for (int index = 0; index < num_completed; ++index, ++out) {
0500           using std::iter_swap;
0501 
0502           
0503           advance(current, indices[index] - current_offset);
0504           current_offset = indices[index];
0505 
0506           
0507           status stat;
0508           stat.m_status = stats[index];
0509           *out = stat;
0510 
0511           
0512           
0513           *current->trivial() = requests[indices[index]];
0514           --start_of_completed;
0515           iter_swap(current, start_of_completed);
0516         }
0517 
0518         
0519         
0520         
0521         std::reverse(start_of_completed, last);
0522         return std::make_pair(out, start_of_completed);
0523       }
0524 
0525       
0526       
0527       n = 0;
0528       current = first;
0529     }
0530   }
0531 
0532   
0533   BOOST_ASSERT(false);
0534 }
0535 
0536 
0537 
0538 
0539 template<typename BidirectionalIterator>
0540 BidirectionalIterator
0541 wait_some(BidirectionalIterator first, BidirectionalIterator last)
0542 {
0543   using std::advance;
0544 
0545   if (first == last)
0546     return first;
0547   
0548   typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0549     difference_type;
0550 
0551   bool all_trivial_requests = true;
0552   difference_type n = 0;
0553   BidirectionalIterator current = first;
0554   BidirectionalIterator start_of_completed = last;
0555   while (true) {
0556     
0557     if (optional<status> result = current->test()) {
0558       using std::iter_swap;
0559 
0560       
0561       --start_of_completed;
0562 
0563       
0564       
0565       if (current == start_of_completed)
0566         return start_of_completed;
0567 
0568       
0569       
0570       iter_swap(current, start_of_completed);
0571 
0572       continue;
0573     }
0574 
0575     
0576     
0577     
0578     all_trivial_requests = all_trivial_requests && current->trivial();
0579 
0580     
0581     ++n;
0582     if (++current == start_of_completed) {
0583         
0584       if (start_of_completed != last)
0585         return start_of_completed;
0586 
0587       
0588       
0589       
0590       if (all_trivial_requests) {
0591         std::vector<MPI_Request> requests;
0592         std::vector<int> indices(n);
0593         requests.reserve(n);
0594         for (current = first; current != last; ++current)
0595           requests.push_back(*current->trivial());
0596 
0597         
0598         int num_completed;
0599         BOOST_MPI_CHECK_RESULT(MPI_Waitsome, 
0600                                (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0601                                 MPI_STATUSES_IGNORE));
0602 
0603         
0604         
0605         int current_offset = 0;
0606         current = first;
0607         for (int index = 0; index < num_completed; ++index) {
0608           using std::iter_swap;
0609 
0610           
0611           advance(current, indices[index] - current_offset);
0612           current_offset = indices[index];
0613 
0614           
0615           
0616           *current->trivial() = requests[indices[index]];
0617           --start_of_completed;
0618           iter_swap(current, start_of_completed);
0619         }
0620 
0621         
0622         return start_of_completed;
0623       }
0624 
0625       
0626       
0627       n = 0;
0628       current = first;
0629     }
0630   }
0631 
0632   
0633   BOOST_ASSERT(false);
0634 }
0635 
0636 
0637 
0638 
0639 
0640 
0641 
0642 
0643 
0644 
0645 
0646 
0647 
0648 
0649 
0650 
0651 
0652 
0653 
0654 
0655 
0656 
0657 
0658 
0659 
0660 
0661 
0662 
0663 
0664 template<typename BidirectionalIterator, typename OutputIterator>
0665 std::pair<OutputIterator, BidirectionalIterator> 
0666 test_some(BidirectionalIterator first, BidirectionalIterator last,
0667           OutputIterator out)
0668 {
0669   BidirectionalIterator current = first;
0670   BidirectionalIterator start_of_completed = last;
0671   while (current != start_of_completed) {
0672     
0673     if (optional<status> result = current->test()) {
0674       using std::iter_swap;
0675 
0676       
0677       *out++ = *result;
0678 
0679       
0680       --start_of_completed;
0681 
0682       
0683       
0684       iter_swap(current, start_of_completed);
0685 
0686       continue;
0687     }
0688 
0689     
0690     ++current;
0691   }
0692 
0693   
0694   
0695   std::reverse(start_of_completed, last);
0696   return std::make_pair(out, start_of_completed);
0697 }
0698 
0699 
0700 
0701 
0702 template<typename BidirectionalIterator>
0703 BidirectionalIterator
0704 test_some(BidirectionalIterator first, BidirectionalIterator last)
0705 {
0706   BidirectionalIterator current = first;
0707   BidirectionalIterator start_of_completed = last;
0708   while (current != start_of_completed) {
0709     
0710     if (optional<status> result = current->test()) {
0711       using std::iter_swap;
0712 
0713       
0714       --start_of_completed;
0715 
0716       
0717       
0718       iter_swap(current, start_of_completed);
0719 
0720       continue;
0721     }
0722 
0723     
0724     ++current;
0725   }
0726 
0727   return start_of_completed;
0728 }
0729 
0730 } } 
0731 
0732 
0733 #endif