DriveHQ Start Menu
Cloud Drive Mapping
Folder Sync
Cloud Backup
True Drop Box
FTP/SFTP Hosting
Group Account
DriveHQ Start Menu
Online File Server
My Storage
|
Manage Shares
|
Publishes
|
Drop Boxes
|
Group Account
WebDAV Drive Mapping
Cloud Drive Home
|
WebDAV Guide
|
Drive Mapping Tool
|
Drive Mapping URL
Complete Data Backup
Backup Guide
|
Online Backup Tool
|
Cloud-to-Cloud Backup
FTP, Email & Web Service
FTP Home
|
FTP Hosting FAQ
|
Email Hosting
|
EmailManager
|
Web Hosting
Help & Resources
About
|
Enterprise Service
|
Partnership
|
Comparisons
|
Support
Quick Links
Security and Privacy
Download Software
Service Manual
Use Cases
Group Account
Online Help
Blog
Contact
Cloud Surveillance
Sign Up
Login
Features
Business Features
Online File Server
FTP Hosting
Cloud Drive Mapping
Cloud File Backup
Email Backup & Hosting
Cloud File Sharing
Folder Synchronization
Group Management
True Drop Box
Full-text Search
AD Integration/SSO
Mobile Access
IP Camera & DVR Solution
More...
Personal Features
Personal Cloud Drive
Backup All Devices
Mobile APPs
Personal Web Hosting
Sub-Account (for Kids)
Home/PC/Kids Monitoring
More...
Software
DriveHQ Drive Mapping Tool
DriveHQ FileManager
DriveHQ Online Backup
DriveHQ Mobile Apps
Pricing
Business Plans & Pricing
Personal Plans & Pricing
Price Comparison with Others
Feature Comparison with Others
Install Mobile App
Sign up
Creating account...
Invalid character in username! Only 0-9, a-z, A-Z, _, -, . allowed.
Username is required!
Invalid email address!
E-mail is required!
Password is required!
Password is invalid!
Password and confirmation do not match.
Confirm password is required!
I accept
Membership Agreement
Please read the Membership Agreement and check "I accept"!
Free Quick Sign-up
Sign-up Page
Log in
Signing in...
Username or e-mail address is required!
Password is required!
Keep me logged in
Quick Login
Forgot Password
Up
Upload
Download
Share
Publish
New Folder
New File
Copy
Cut
Delete
Paste
Rate
Upgrade
Rotate
Effect
Edit
Slide
History
// Copyright (C) 2006 Douglas Gregor
. // 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
#include
#include
// for std::iterator_traits #include
#include
// for std::pair #include
// for iter_swap, reverse #include
#include
#include
#include
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
std::pair
wait_any(ForwardIterator first, ForwardIterator last) { using std::advance; BOOST_ASSERT(first != last); typedef typename std::iterator_traits
::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 (optional
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
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
optional
> test_any(ForwardIterator first, ForwardIterator last) { for (ForwardIterator current = first; first != last; ++first) { // Check if we have found a completed request. If so, return it. if (optional
result = current->test()) return std::make_pair(*result, current); } // We found nothing return optional
>(); } /** * @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
OutputIterator wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out) { typedef typename std::iterator_traits
::difference_type difference_type; using std::distance; difference_type num_outstanding_requests = distance(first, last); std::vector
results(num_outstanding_requests); std::vector
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
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
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
stats(num_outstanding_requests); BOOST_MPI_CHECK_RESULT(MPI_Waitall, (num_outstanding_requests, &requests[0], &stats[0])); for (std::vector
::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
void wait_all(ForwardIterator first, ForwardIterator last) { typedef typename std::iterator_traits
::difference_type difference_type; using std::distance; difference_type num_outstanding_requests = distance(first, last); std::vector
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
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
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
optional
test_all(ForwardIterator first, ForwardIterator last, OutputIterator out) { std::vector
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
(); requests.push_back(first->m_requests[0]); } int flag = 0; int n = requests.size(); std::vector
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
(); } } /** * \overload */ template
bool test_all(ForwardIterator first, ForwardIterator last) { std::vector
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
std::pair
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
::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
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
requests; std::vector
indices(n); std::vector
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
BidirectionalIterator wait_some(BidirectionalIterator first, BidirectionalIterator last) { using std::advance; if (first == last) return first; typedef typename std::iterator_traits
::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
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
requests; std::vector
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
std::pair
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
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
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
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
nonblocking.hpp
Page URL
File URL
Prev
13/22
Next
Download
( 25 KB )
Note: The DriveHQ service banners will NOT be displayed if the file owner is a paid member.
Comments
Total ratings:
0
Average rating:
Not Rated
Would you like to comment?
Join DriveHQ
for a free account, or
Logon
if you are already a member.