asynchronous functions in c++
DESCRIPTION
Early dabble with futures in C++ using meta-programming and templatesTRANSCRIPT
![Page 1: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/1.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Functions in C++
The Generic Approach
Schalk W. Cronjé
20 April 2005
![Page 2: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/2.jpg)
ACCU 2005© Schalk W. Cronjé
Why asynchronous processing?
● All “real-time” systems require some form of asynchronous architecture.
● Anything that needs to do background processing whilst attending to other tasks or user input require an asynchronous architecture of some sort
![Page 3: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/3.jpg)
ACCU 2005© Schalk W. Cronjé
Cost of Switching Architecture
In any standard implementation there is usually a significant cost of effort and time in switching between different asynchronous mediums.
![Page 4: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/4.jpg)
ACCU 2005© Schalk W. Cronjé
McCall's Quality Factors
● Correctness● Reliability● Usability● Maintainability● Portability● Efficiency
● Testability● Flexibility● Integrity● Reusability● Interoperability
![Page 5: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/5.jpg)
ACCU 2005© Schalk W. Cronjé
Not just Threads!
Asynchronous execution extends far beyond just threads.
Threads are but a part of a much bigger picture.
Since threads are a known quantity they remain a good metaphor to explain the concepts surrounding asynchronous C++ functions
![Page 6: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/6.jpg)
ACCU 2005© Schalk W. Cronjé
Prior Art
● Kevlin HenneyACCU 2003 / 2004http://www.two-sdg.demon.co.uk/curbralan/papers/accu/MoreC++Threading.pdf
● Drazen DotlicC++ Users Journal, Nov 2004
● Boost Threads
● Boost Signals & Slots
![Page 7: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/7.jpg)
ACCU 2005© Schalk W. Cronjé
Design Goals
● The ability to execute a free function, member function or functor asynchronously without regard to the asynchronous medium
● The ability to change asynchronous mediums with as little code change as possible
● Keep it portable
![Page 8: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/8.jpg)
ACCU 2005© Schalk W. Cronjé
The 5 Essentials
● Launching a function asynchronously
● Knowing whether the function has completed
● Waiting for a function to complete
● Collecting the result
● Asynchronous notification
![Page 9: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/9.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Primitives
● Threads (+mutexes etc.)● Async IO● C Signals
Of these three only threads can be ported easily and can play nicely with C++. Therefore threads can be used to build asynchronous mediums without being used as one itself.
![Page 10: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/10.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Mediums
● Threads ● Thread Pools● Task Queues● Spawned Processes● XML-RPC & SOAP● Interprocess Message Queues
![Page 11: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/11.jpg)
ACCU 2005© Schalk W. Cronjé
To detach or not
● A detached task is one on which synchronous waits cannot be performed
● Win32 & Pthreads distinguish between detached and non-detached threads.
● Non-detached threads require a cleanup to be performed after thread has terminated
● boost::threads uses d-tor to detach a thread● It is debatable whether all tasks should
automatically be created in a detached state
![Page 12: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/12.jpg)
ACCU 2005© Schalk W. Cronjé
Building a Generic Interface
![Page 13: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/13.jpg)
ACCU 2005© Schalk W. Cronjé
Creating a Task
async_id create_task( Medium, Functor );async_id create_task( Medium, Functor );
template <typename Medium>create_task(
Medium const& async_medium_,
);
typename async_traits<Medium>::id_type
typename async_traits<Medium>::functor_type f_
![Page 14: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/14.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #1
template <typename Medium>struct async_traits {
};
template <typename Medium>struct async_traits {
};
typedef implementation-defined id_type;typedef implementation-defined functor_type;static id_type create(Medium,functor_type);
id_type must be non-native, but lightweight copyable
![Page 15: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/15.jpg)
ACCU 2005© Schalk W. Cronjé
// Simple Medium exampleclass thread_id;class SimpleThreader{
public:
// Creates a thread, runs the functionthread_id create( boost::function< int() > ) const;
};
![Page 16: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/16.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #1
template <>struct async_traits<SimpleThreader> {
};
template <>struct async_traits<SimpleThreader> {
};
typedef SimpleThreader::thread_id id_type;typedef boost::function< int()> functor_type;
![Page 17: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/17.jpg)
ACCU 2005© Schalk W. Cronjé
boost::function
The Boost.Function library contains a family of class templates that are function object wrappers. The notion is similar to a generalized callback.
http://www.boost.org/doc/html/function.html
![Page 18: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/18.jpg)
ACCU 2005© Schalk W. Cronjé
// boost::function makes easy work of wrapping// pointers to functionsint my_func( int,int );boost::function< int(int,int) > f1 = &my_func;std::cout << f1( 3, 4 );// and even member functionsusing std::string;boost::function< string::size_type(string const*) > f2= &string::size;string s2(“Hello, World”);std::cout << f2(&s2);
![Page 19: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/19.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #1
template <>struct async_traits<SimpleThreader> {
};
template <>struct async_traits<SimpleThreader> {
};
typedef SimpleThreader::thread_id id_type;typedef boost::function< int()> functor_type;
static id_type create( SimpleThreader const& medium_, functor_type f_ ){return medium_.create(f_);}
constness is not a requirement
![Page 20: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/20.jpg)
ACCU 2005© Schalk W. Cronjé
// Calculate information flow of all source files// in a directoryint calc_IF4( const char* directory_ );
SimpleThreader threader;
thread_id id= create_task( threader, boost::bind( &calc_IF4,”/myproj” )
);
![Page 21: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/21.jpg)
ACCU 2005© Schalk W. Cronjé
Completing create_tasktemplate <typename Medium>typename async_traits<Medium>::id_typecreate_task(
Medium const& async_medium_,typename async_traits<Medium>::functor_type f_
){
}
return async_traits<Medium>::create(async_medium_,f_
);create_task can becomplemented by a version taking a mutable reference to the asynchronous medium
![Page 22: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/22.jpg)
ACCU 2005© Schalk W. Cronjé
Restricting the return typetemplate <typename Medium>typename async_traits<Medium>::id_typecreate_task(
Medium const& async_medium_,typename async_traits<Medium>::functor_type f_
){
}
return async_traits<Medium>::create(async_medium_,f_
);
BOOST_STATIC_ASSERT(( boost::is_object<typenameasync_traits<Medium>::id_type>::value ));
![Page 23: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/23.jpg)
ACCU 2005© Schalk W. Cronjé
// Example thread_idclass thread_id{
friend class SimpleThreader;public:
typedef SimpleThreader medium_type;thread_id();thread_id(thread_id const&);bool done() const;void wait() const;int const* data() const;
private:class low_level_impl;boost:shared_ptr<low_level_impl> m_pImpl;thread_id(low_level_impl*);
};
![Page 24: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/24.jpg)
ACCU 2005© Schalk W. Cronjé
Waiting for a Task
void wait_task( task_id );bool task_completed( task_id );
template <typename TaskID>voidwait_task( TaskID const& );template <typename TaskID>booltask_completed( TaskID const& );
![Page 25: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/25.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #2
template <typename Medium>struct async_traits {
};
template <typename Medium>struct async_traits {
};
static void wait(id_type);static bool completed(id_type);static bool detached(id_type);
typedef implementation-defined id_type;typedef implementation-defined functor_type;static id_type create(Medium,functor_type);
![Page 26: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/26.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #2
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type;
};
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type;
};
static bool completed( id_type const& id_ ) { return id_.done();} static void wait( id_type const& id_ ) { id_.wait(); } static bool detached( id_type const& id_ );
![Page 27: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/27.jpg)
ACCU 2005© Schalk W. Cronjé
// Having started a task to calculate IF4// we can check whether a task has completed
if( !task_completed( id ) ) {
// do something else first}// or just simply wait for task to completewait_task( id );
![Page 28: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/28.jpg)
ACCU 2005© Schalk W. Cronjé
Completing wait_tasktemplate <typename TaskID>voidwait_task( TaskID const& task_id_ ){
}
typedef typename async_traits_of<TaskID>::type traits;
if( !task_completed(task_id_) ){
if( traits::detached(task_id_) )throw invalid_operation;
elsetraits::wait(task_id_);
}
![Page 29: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/29.jpg)
ACCU 2005© Schalk W. Cronjé
async_traits_oftemplate <typename TaskID>struct async_traits_of{
typedef typename async_traits<typename TaskID::medium_type
> type;};
Easy to specialise if necessary
![Page 30: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/30.jpg)
ACCU 2005© Schalk W. Cronjé
Collecting the Result
result_pointer task_result( task_id );
template <typename TaskID>task_result( TaskID const& task_id_ );typename async_pointer_of<TaskID>::type
If task has not completedresult is null
![Page 31: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/31.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #3
template <typename Medium>struct async_traits {
};
template <typename Medium>struct async_traits {
};
typedef implementation-defined result_type;typedef implementation-defined result_pointer;static result_pointer get_result(id_type);
typedef implementation-defined id_type;typedef implementation-defined functor_type;static id_type create(Medium,functor_type);static void wait(id_type);static bool completed(id_type);static bool detached(id_type);
![Page 32: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/32.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #3
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type;
};
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type;
};
typedef int result_type; typedef int const* result_ptr; static result_ptr get_result( id_type const& id_ ) {return id_.data();}
![Page 33: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/33.jpg)
ACCU 2005© Schalk W. Cronjé
Completing task_resulttemplate <typename TaskID>typename async_pointer_of<TaskID>::typetask_result( TaskID const& task_id_ ){
}
typedef typename async_traits_of<TaskID>::type traits;
if( !task_completed(task_id_) )return async_pointer_of<TaskID>::type();
elsereturn traits::get_result(task_id_);
BOOST_STATIC_ASSERT(( !boost::is_void<typename traits::result_type>::value ));
![Page 34: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/34.jpg)
ACCU 2005© Schalk W. Cronjé
Detaching & Notification
● In order to achieve true asynchronous functions notifications must be implemented
● If a function is launched in a detached mode the only way to know when it has finished is via a callback or alternative notification
● It is important that notifications are asynchronous safe – at least for the medium on which they are applied
![Page 35: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/35.jpg)
ACCU 2005© Schalk W. Cronjé
Creating a Detached Task
async_id create_task( Medium, Functor, Notifier );async_id create_task( Medium, Functor, Notifier );
template <typename Medium>create_task(
Medium const& async_medium_,
);
typename async_traits<Medium>::id_type
typename async_traits<Medium>::functor_type f_, boost::function<void( typename async_traits<Medium>::id_type )> notify_
![Page 36: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/36.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #4template <typename Medium>struct async_traits {
};
template <typename Medium>struct async_traits {
};
typedef boost::function<void(id_type)> notification_type;static id_type create_detached (Medium,functor_type,notification_type);
typedef implementation-defined id_type;typedef implementation-defined functor_type;typedef implementation-defined result_type;typedef implementation-defined result_pointer;static id_type create(Medium,functor_type);static void wait(id_type);static bool completed(id_type);static bool detached(id_type);static result_pointer get_result(id_type);
![Page 37: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/37.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits #3
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type; typedef boost::function< int()> functor_type;
};
template <>struct async_traits<SimpleThreader> { typedef SimpleThreader::thread_id id_type; typedef boost::function< int()> functor_type;
};
typedef boost::function< void(id_type) > notification_type; static id_type create_detached( SimpleThreader const&, function_type, notification_type );
![Page 38: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/38.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Traits Summarytemplate <typename Medium>struct async_traits {
};
template <typename Medium>struct async_traits {
};
typedef implementation-defined id_type;typedef implementation-defined functor_type;typedef implementation-defined result_type;typedef implementation-defined result_pointer;typedef boost::function<void(id_type) notification_type;static id_type create(Medium,functor_type);static id_type create_detached (Medium,functor_type,notification_type);static void wait(id_type);static bool completed(id_type);static bool detached(id_type);static result_pointer get_result(id_type);
![Page 39: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/39.jpg)
ACCU 2005© Schalk W. Cronjé
Asynchronous Function Summary
id_type create_task( Medium, Functor );id_type create_task( Medium, Functor, Notifier );void wait_task( id_type );bool task_completed( id_type );result_pointer task_result( id_type );
![Page 40: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/40.jpg)
ACCU 2005© Schalk W. Cronjé
Additional Considerations
● Task identifiers must be lightweight copyable
● A completed task's result must be available until the last task identifier for that task has been removed.
● boost::shared_ptr generally the easiest way to accomplish both the above
![Page 41: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/41.jpg)
ACCU 2005© Schalk W. Cronjé
Extending the Traits
● Some mediums might not be detachable. ● This can be handled by adding an additional
is_detachable constant.● create_task(m,f,n) can assert on this during
compile time.
![Page 42: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/42.jpg)
ACCU 2005© Schalk W. Cronjé
Extending Traitstemplate <typename Medium>struct async_traits {
BOOST_STATIC_CONSTANT(bool,is_detachable=true);// ...
};template <typename Medium>typename async_traits<Medium>::task_idcreate_task( /* parms omitted for brevity */ ){
BOOST_STATIC_ASSERT(async_traits<Medium>::is_detachable);}
template <typename Medium>struct async_traits {
BOOST_STATIC_CONSTANT(bool,is_detachable=true);// ...
};template <typename Medium>typename async_traits<Medium>::task_idcreate_task( /* parms omitted for brevity */ ){
BOOST_STATIC_ASSERT(async_traits<Medium>::is_detachable);}
![Page 43: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/43.jpg)
ACCU 2005© Schalk W. Cronjé
Start with simplethreaded app
Improve performanceby using thread poolsor task queues
Use distributed computing by goingout of process orout of host
![Page 44: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/44.jpg)
ACCU 2005© Schalk W. Cronjé
Concluding
![Page 45: Asynchronous Functions In C++](https://reader034.vdocument.in/reader034/viewer/2022042601/554f5497b4c905b9508b4fbe/html5/thumbnails/45.jpg)
ACCU 2005© Schalk W. Cronjé
A generic approach to asynchronous execution is not a golden solution, but it goes a long way to decoupling the asynchronous architecture from
the business logic.
It allows for selection of an architecture based upon underlying platform without having to modify the overlaying business application