@ -4,10 +4,12 @@
//
// Copyright (C) 2019 Intel Corporation
# include <opencv2/gapi/gcomputation_async.hpp>
# include <opencv2/gapi/gcomputation.hpp>
# include <opencv2/gapi/gcompiled_async.hpp>
# include <opencv2/gapi/gcompiled.hpp>
# include <opencv2/gapi/gasync_context.hpp>
# include <condition_variable>
@ -19,11 +21,11 @@
namespace {
//This is a tool to move initialize captures of a lambda in C++11
template < typename T >
struct move_through_copy {
struct copy_through_move {
T value ;
move_through_copy ( T & & g ) : value ( std : : move ( g ) ) { }
move_through_copy ( move_through_copy & & ) = default ;
move_through_copy ( move_through_copy const & lhs ) : move_through_copy ( std : : move ( const_cast < move_through_copy & > ( lhs ) ) ) { }
copy_through_move ( T & & g ) : value ( std : : move ( g ) ) { }
copy_through_move ( copy_through_move & & ) = default ;
copy_through_move ( copy_through_move const & lhs ) : copy_through_move ( std : : move ( const_cast < copy_through_move & > ( lhs ) ) ) { }
} ;
}
@ -80,6 +82,7 @@ public:
} } ;
}
}
std : : unique_lock < std : : mutex > lck { mtx } ;
bool first_task = q . empty ( ) ;
q . push ( std : : move ( t ) ) ;
@ -108,8 +111,12 @@ async_service the_ctx;
}
namespace {
template < typename f_t >
std : : exception_ptr call_and_catch ( f_t & & f ) {
template < typename f_t , typename context_t >
std : : exception_ptr call_and_catch ( f_t & & f , context_t & & ctx ) {
if ( std : : forward < context_t > ( ctx ) . isCanceled ( ) ) {
return std : : make_exception_ptr ( GAsyncCanceled { } ) ;
}
std : : exception_ptr eptr ;
try {
std : : forward < f_t > ( f ) ( ) ;
@ -120,15 +127,21 @@ std::exception_ptr call_and_catch(f_t&& f){
return eptr ;
}
template < typename f_t , typename callback_t >
void call_with_callback ( f_t & & f , callback_t & & cb ) {
auto eptr = call_and_catch ( std : : forward < f_t > ( f ) ) ;
struct DummyContext {
bool isCanceled ( ) const {
return false ;
}
} ;
template < typename f_t , typename callback_t , typename context_t >
void call_with_callback ( f_t & & f , callback_t & & cb , context_t & & ctx ) {
auto eptr = call_and_catch ( std : : forward < f_t > ( f ) , std : : forward < context_t > ( ctx ) ) ;
std : : forward < callback_t > ( cb ) ( eptr ) ;
}
template < typename f_t >
void call_with_futute ( f_t & & f , std : : promise < void > & p ) {
auto eptr = call_and_catch ( std : : forward < f_t > ( f ) ) ;
template < typename f_t , typename context_t >
void call_with_futur e ( f_t & & f , std : : promise < void > & p , context_t & & ctx ) {
auto eptr = call_and_catch ( std : : forward < f_t > ( f ) , std : : forward < context_t > ( ctx ) ) ;
if ( eptr ) {
p . set_exception ( eptr ) ;
}
@ -138,33 +151,76 @@ void call_with_futute(f_t&& f, std::promise<void>& p){
}
} //namespace
bool GAsyncContext : : cancel ( ) {
bool expected = false ;
bool updated = cancelation_requested . compare_exchange_strong ( expected , true ) ;
return updated ;
}
bool GAsyncContext : : isCanceled ( ) const {
return cancelation_requested . load ( ) ;
}
const char * GAsyncCanceled : : what ( ) const noexcept {
return " GAPI asynchronous operation was canceled " ;
}
//For now these async functions are simply wrapping serial version of apply/operator() into a functor.
//These functors are then serialized into single queue, which is processed by a devoted background thread.
void async_apply ( GComputation & gcomp , std : : function < void ( std : : exception_ptr ) > & & callback , GRunArgs & & ins , GRunArgsP & & outs , GCompileArgs & & args ) {
//TODO: use move_through_copy for all args except gcomp
//TODO: use copy_through_move for all args except gcomp
//TODO: avoid code duplication between versions of "async" functions
auto l = [ = ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcomp . apply ( std : : move ( ins ) , std : : move ( outs ) , std : : move ( args ) ) ;
} ;
call_with_callback ( apply_l , std : : move ( callback ) ) ;
call_with_callback ( apply_l , std : : move ( callback ) , DummyContext { } ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
}
std : : future < void > async_apply ( GComputation & gcomp , GRunArgs & & ins , GRunArgsP & & outs , GCompileArgs & & args ) {
move_through_copy < std : : promise < void > > prms { { } } ;
copy_through_move < std : : promise < void > > prms { { } } ;
auto f = prms . value . get_future ( ) ;
auto l = [ = ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcomp . apply ( std : : move ( ins ) , std : : move ( outs ) , std : : move ( args ) ) ;
} ;
call_with_futute ( apply_l , prms . value ) ;
call_with_future ( apply_l , prms . value , DummyContext { } ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
return f ;
}
void async_apply ( GComputation & gcomp , std : : function < void ( std : : exception_ptr ) > & & callback , GRunArgs & & ins , GRunArgsP & & outs , GCompileArgs & & args , GAsyncContext & ctx ) {
//TODO: use copy_through_move for all args except gcomp
auto l = [ = , & ctx ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcomp . apply ( std : : move ( ins ) , std : : move ( outs ) , std : : move ( args ) ) ;
} ;
call_with_callback ( apply_l , std : : move ( callback ) , ctx ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
}
std : : future < void > async_apply ( GComputation & gcomp , GRunArgs & & ins , GRunArgsP & & outs , GCompileArgs & & args , GAsyncContext & ctx ) {
copy_through_move < std : : promise < void > > prms { { } } ;
auto f = prms . value . get_future ( ) ;
auto l = [ = , & ctx ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcomp . apply ( std : : move ( ins ) , std : : move ( outs ) , std : : move ( args ) ) ;
} ;
call_with_future ( apply_l , prms . value , ctx ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
return f ;
}
void async ( GCompiled & gcmpld , std : : function < void ( std : : exception_ptr ) > & & callback , GRunArgs & & ins , GRunArgsP & & outs ) {
@ -173,21 +229,48 @@ void async(GCompiled& gcmpld, std::function<void(std::exception_ptr)>&& callback
gcmpld ( std : : move ( ins ) , std : : move ( outs ) ) ;
} ;
call_with_callback ( apply_l , std : : move ( callback ) ) ;
call_with_callback ( apply_l , std : : move ( callback ) , DummyContext { } ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
}
void async ( GCompiled & gcmpld , std : : function < void ( std : : exception_ptr ) > & & callback , GRunArgs & & ins , GRunArgsP & & outs , GAsyncContext & ctx ) {
auto l = [ = , & ctx ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcmpld ( std : : move ( ins ) , std : : move ( outs ) ) ;
} ;
call_with_callback ( apply_l , std : : move ( callback ) , ctx ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
}
std : : future < void > async ( GCompiled & gcmpld , GRunArgs & & ins , GRunArgsP & & outs ) {
move_through_copy < std : : promise < void > > prms { { } } ;
copy_through_move < std : : promise < void > > prms { { } } ;
auto f = prms . value . get_future ( ) ;
auto l = [ = ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcmpld ( std : : move ( ins ) , std : : move ( outs ) ) ;
} ;
call_with_futute ( apply_l , prms . value ) ;
call_with_future ( apply_l , prms . value , DummyContext { } ) ;
} ;
impl : : the_ctx . add_task ( l ) ;
return f ;
}
std : : future < void > async ( GCompiled & gcmpld , GRunArgs & & ins , GRunArgsP & & outs , GAsyncContext & ctx ) {
copy_through_move < std : : promise < void > > prms { { } } ;
auto f = prms . value . get_future ( ) ;
auto l = [ = , & ctx ] ( ) mutable {
auto apply_l = [ & ] ( ) {
gcmpld ( std : : move ( ins ) , std : : move ( outs ) ) ;
} ;
call_with_future ( apply_l , prms . value , ctx ) ;
} ;
impl : : the_ctx . add_task ( l ) ;