Last active
September 7, 2024 09:44
-
-
Save inetic/dc9081baf45ec4b60037 to your computer and use it in GitHub Desktop.
Example usage of boost::asio::async_result
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example of how to use boost::asio::async_result | |
#include <iostream> | |
#include <boost/asio.hpp> | |
#if BOOST_VERSION >= 106600 | |
template<typename CompletionToken> | |
typename boost::asio::async_result | |
<CompletionToken, void(boost::system::error_code, std::string)>::return_type | |
my_fancy_async_operation( boost::asio::io_service& ios | |
, const std::string& message | |
, CompletionToken&& token) | |
{ | |
namespace asio = boost::asio; | |
namespace system = boost::system; | |
using Sig = void(system::error_code, std::string); | |
using Result = asio::async_result<CompletionToken, Sig>; | |
using Handler = typename Result::completion_handler_type; | |
Handler handler(std::forward<decltype(token)>(token)); | |
Result result(handler); | |
ios.post([handler, message]() mutable { | |
handler(system::error_code(), message); | |
}); | |
return result.get(); | |
} | |
#else | |
// Note: the handler signatures here must contain | |
// boost::system::error_code as first argument (not std::error_code) | |
// for asio to understand it is to indicate errors. | |
template<typename CompletionToken> | |
typename boost::asio::async_result | |
< typename boost::asio::handler_type< CompletionToken | |
, void(boost::system::error_code, std::string) | |
>::type | |
>::type | |
my_fancy_async_operation( boost::asio::io_service& ios | |
, const std::string& message | |
, CompletionToken&& token) | |
{ | |
namespace asio = boost::asio; | |
namespace system = boost::system; | |
using handler_type = typename asio::handler_type | |
<CompletionToken, void(system::error_code, std::string)>::type; | |
handler_type handler(std::forward<decltype(token)>(token)); | |
// The result must be defined here, otherwise we'll get segmentation | |
// fault when using coroutines (don't understand why though). | |
asio::async_result<handler_type> result(handler); | |
ios.post([handler, message]() mutable { | |
handler(system::error_code(), message); | |
}); | |
return result.get(); | |
} | |
#endif | |
// Link flags: -lboost_coroutine // If using coroutines | |
// -lboost_context // If using coroutines | |
// -lboost_system // For asio | |
// -lpthread // If using futures | |
#define USE_CALLBACKS 1 | |
#define USE_FUTURES 1 | |
#define USE_COROUTINES 1 | |
#if USE_FUTURES | |
# include <thread> | |
# include <boost/asio/use_future.hpp> | |
#endif | |
#if USE_COROUTINES | |
# include <boost/asio/spawn.hpp> | |
#endif | |
int main() { | |
using namespace std; | |
using namespace boost; | |
asio::io_service ios; | |
#if USE_CALLBACKS | |
{ | |
my_fancy_async_operation( ios | |
, "handler" | |
, []( system::error_code, const string& msg) { | |
cout << "hello " << msg << endl; | |
}); | |
ios.run(); | |
} | |
#endif | |
#if USE_FUTURES | |
ios.reset(); | |
{ | |
asio::io_service::work work(ios); | |
thread io_thread([&ios]() { ios.run(); }); | |
try { | |
auto msg = my_fancy_async_operation(ios | |
, "future" | |
, boost::asio::use_future).get(); | |
cout << "hello " << msg << endl; | |
} | |
catch (boost::system::system_error error) { | |
// ... | |
} | |
ios.stop(); | |
io_thread.join(); | |
} | |
#endif | |
#if USE_COROUTINES | |
ios.reset(); | |
{ | |
boost::asio::spawn(ios, [&ios](boost::asio::yield_context yield) { | |
system::error_code error; | |
auto msg = my_fancy_async_operation(ios, "coroutine", yield[error]); | |
cout << "hello " << msg << endl; | |
}); | |
ios.run(); | |
} | |
#endif | |
} |
Great! Have long been searching for a good example. Looking at Asio code directly is just too confusing.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Excellent! Exactly what I was looking for.