William E. Kempf wrote: >> Here's some compilable code, to put things in perspective: > > Thanks. This helps me, at least. > >> #include <boost/detail/lightweight_mutex.hpp> >> #include <boost/function.hpp> >> #include <boost/bind.hpp> >> #include <stdexcept> >> #include <string> >> #include <iostream> >> >> template<class R> class async_call >> { >> public: >> >> template<class F> explicit async_call(F f): f_(f), ready_(false) >> { >> } >> >> void operator()() >> { >> mutex_type::scoped_lock lock(mutex_); >> new(result_) R(f_()); >> ready_ = true; >> } > > Hmm... is this truly portable? Don't you have to use the same > techniques as optional<> here... or even just use optional<> in the > implementation? Also, though not on subject with discussion of the > design, it's probably a bad idea to lock the mutex in this way > (mutexes shouldn't be held for extensive periods of time), though the > alternative implementation requires 2 copies of R and a condition for > waiting on the result.
No, this is not portable; it's also incorrect since it doesn't execute ~R when it should, and I didn't block copy/assignment. Using optional<> would be a much better choice. This is only a sketch. I've used the "illustrative" mutex to specify the synchronization semantics, not implementation. >> // step 2: execute an async_call >> call(); > > This example, and the implementation above, are just complex > synchronous calls. I assume you really meant for either the > constructor or this call to also take an Executor concept? This line could be boost::thread exec( ref(call) ); or boost::thread_pool pool; pool.dispatch( ref(call) ); I didn't have a prebuilt Boost.Threads library handy when I wrote the code (rather quickly) so I used a plain call. >> // step 3: obtain result >> try >> { >> std::cout << call.result() << std::endl; >> } >> catch(std::exception const & x) >> { >> std::cout << x.what() << std::endl; >> } >> } > > The one "issue" I see with using operator() to invoke the function is > the race conditions that can occur if the user calls this multiple > times. I'd consider it a non-issue personally, since you'd have to > go out of your way to use this design incorrectly, but thought I > should at least point it out. Since operator() is synchronized, i don't see a race... am I missing something? > Actually, there's another minor issue as well. The user can call > operator() and then let the async_call go out of scope with out ever > calling result(). Mayhem would ensue. The two options for dealing > with this are to either block in the destructor until the call has > completed or to simply document this as undefined behavior. Yes, good point, I missed that. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost