
Hi, the combination of asio and coroutines would seem to represent a little bit of magic (layering a linear code model over an async event framework and without the attendant issues involved in multithreading). However the coroutine library seems to be exception throwing in an unanticipated way when performing a wait on a future<> during the execution of an asio async operation. I am following the documention and am reasonably familiar with asio from other projects - but have only just worked through some of the examples from the coroutines documention. i am using the vault freeze version of coroutines from 2006 - i understand from perusing these lists that the library author is currently rewritting boost::coroutine around a continuation framework to simplify and in the hope that the library may be an official boost inclusion. Much kudos for contributing to c++ in a significant way ;-) the documentation seems to have some errors http://www.crystalclearsoftware.com/soc/coroutine/coroutine/asio.html - guidance is given to use shared_coroutine in preference to coroutine in asio context although this is not present in the example - asio uses the boost::system error classes in the boost namespace when not freestanding - the example calls wait() on source which is a socket type rather than a future I have attempted to work up an example which looks logical - but cant get around the throw that occurs at /boost/coroutine/detail/context_base.hpp:213 // linux 2.6.23, g++ (GCC) 4.1.2 // g++ -g main.cpp -lboost_coroutine-mt -lboost_system-mt #include <iostream> #include <boost/bind.hpp> #include <boost/ref.hpp> #include <boost/coroutine/coroutine.hpp> #include <boost/coroutine/generator.hpp> #include <boost/coroutine/future.hpp> #include <boost/asio.hpp> namespace coro = boost::coroutines; using namespace coro; typedef boost::asio::io_service service_type; //typedef coro::coroutine< void()> foo_coroutine_type; //typedef coro::coroutine< void( service_type &service)> foo_coroutine_type; typedef coro::shared_coroutine< void( service_type &service)> foo_coroutine_type; void foo( foo_coroutine_type::self &self, service_type &service) { typedef boost::system::error_code error_type; typedef boost::asio::ip::tcp::resolver::query query_type; typedef boost::asio::ip::tcp::resolver::iterator iterator_type; boost::asio::ip::tcp::resolver resolver( service); query_type query( "www.boost.org", 80 ); coro::future< error_type, iterator_type> future( self); resolver.async_resolve( query, coro::make_callback( future)); assert( !future); // wait throws here --> /boost/coroutine/detail/context_base.hpp:213 coro::wait( future); assert( future); error_type &error = future->get< 0>(); if( error) std::cout << "error resolving " << error.message() << std::endl; else { iterator_type ip = future->get< 1>(); while( ip != iterator_type()) std::cout << ip->endpoint() << std::endl; } } int main() { service_type service; foo_coroutine_type cfoo( boost::bind( &foo, _1, boost::ref( service))); cfoo(); // service.post( boost::bind( &foo_coroutine_type::operator(void ), &cfoo)); service.run(); }

atkinson julian wrote:
Hi, the combination of asio and coroutines would seem to represent a little bit of magic (layering a linear code model over an async event framework and without the attendant issues involved in multithreading).
Yes, it would be pretty cool. However, couldn't the syntax be directly that of blocking asio calls? coro::future<error_type, iterator_type> future(self); resolver.async_resolve(query, coro::make_callback(future)); coro::wait(future); is really the same thing as tuple<error_type, iterator_type> result = resolver.resolve(query);

On Fri, Jul 25, 2008 at 2:44 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
atkinson julian wrote:
Hi, the combination of asio and coroutines would seem to represent a little bit of magic (layering a linear code model over an async event framework and without the attendant issues involved in multithreading).
Yes, it would be pretty cool. However, couldn't the syntax be directly that of blocking asio calls?
coro::future<error_type, iterator_type> future(self); resolver.async_resolve(query, coro::make_callback(future)); coro::wait(future);
is really the same thing as
tuple<error_type, iterator_type> result = resolver.resolve(query);
Yes, it is. The point is that you can have many coroutines in flight at the same time. With the blocking call variant you must have multiple threads to do the same thing. Julian: sorry for not replying, I'm far from a compilable boost.coroutine installation ATM and cannot test your code (and probably I won't be for two weeks). BTW, yes, the example in the doc is wrong and your code should Just work; if it doesn't it is a bug in the library. -- gpd

To hopefully ease your mind - there was no bug in boost::coroutine, i simply failed to pass the std::no_throw on coroutine invocation and the asio component of the doc was simply a little brief for a newbie like me. The justification and need for the no throw wrt futures is explained well elsewhere. I really hope its possible to find the time/ motivation to do what you believe is needed re boost inclusion since it represents such a powerful (correct) programming model that can be applied in many area's - networking / actor model / simulation etc. the non thread migratability of coroutines is also easy to adapt to - by employing a couple of asio pumps. After discovering my mistake and progressing a little I now have 1000 simultanious and active connections being managed trivially on an under powered laptop . This with a very straight-forward and linear code model (and with no expensive context switches or synchronization primitves needed at this particular layer level ) thanks to the coroutine support. On Fri, Jul 25, 2008 at 1:27 PM, Giovanni Piero Deretta <gpderetta@gmail.com
wrote:
atkinson julian wrote:
Hi, the combination of asio and coroutines would seem to represent a
On Fri, Jul 25, 2008 at 2:44 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote: little
bit of magic (layering a linear code model over an async event framework and without the attendant issues involved in multithreading).
Yes, it would be pretty cool. However, couldn't the syntax be directly that of blocking asio calls?
coro::future<error_type, iterator_type> future(self); resolver.async_resolve(query, coro::make_callback(future)); coro::wait(future);
is really the same thing as
tuple<error_type, iterator_type> result = resolver.resolve(query);
Yes, it is. The point is that you can have many coroutines in flight at the same time. With the blocking call variant you must have multiple threads to do the same thing.
Julian: sorry for not replying, I'm far from a compilable boost.coroutine installation ATM and cannot test your code (and probably I won't be for two weeks). BTW, yes, the example in the doc is wrong and your code should Just work; if it doesn't it is a bug in the library.
-- gpd _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

on Sat Jul 26 2008, "atkinson julian" <julian.atkinson71-AT-gmail.com> wrote:
To hopefully ease your mind - there was no bug in boost::coroutine, i simply failed to pass the std::no_throw on coroutine invocation and the asio component of the doc was simply a little brief for a newbie like me. The justification and need for the no throw wrt futures is explained well elsewhere.
I really hope its possible to find the time/ motivation to do what you believe is needed re boost inclusion since it represents such a powerful (correct) programming model that can be applied in many area's - networking / actor model / simulation etc. the non thread migratability of coroutines is also easy to adapt to - by employing a couple of asio pumps.
I, too, hope you can get coroutine reviewed and accepted. It sounds really cool. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (4)
-
atkinson julian
-
David Abrahams
-
Giovanni Piero Deretta
-
Mathias Gaunard