Last active
August 29, 2015 14:01
-
-
Save RossBencina/4925236fa88f1a5e26ac to your computer and use it in GitHub Desktop.
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
// Template-based async method continuation idea by Ross Bencina <[email protected]> May 2014. | |
// see: https://groups.google.com/forum/#!topic/comp.lang.c++.moderated/ryhWI6cX3Ko | |
#include <iostream> | |
#include <list> | |
typedef void (*async_callback_fn_t)(void*); | |
struct PendingSimulatedTaskCallback{ | |
async_callback_fn_t simulatedAsyncCallbackFn_; | |
void *simulatedAsyncCallbackData_; | |
PendingSimulatedTaskCallback( async_callback_fn_t f, void *d ) | |
: simulatedAsyncCallbackFn_(f) | |
, simulatedAsyncCallbackData_(d) {} | |
void invokeCompletionCallback() | |
{ | |
(*simulatedAsyncCallbackFn_)(simulatedAsyncCallbackData_); | |
} | |
}; | |
std::list<PendingSimulatedTaskCallback> pendingTasks_; | |
void initiateSimulatedTaskWithAsyncCallback( async_callback_fn_t fn, void *data ) | |
{ | |
pendingTasks_.push_back(PendingSimulatedTaskCallback(fn,data)); | |
} | |
bool simulatedTaskIsPending() | |
{ | |
return !pendingTasks_.empty(); | |
} | |
void simulateAsyncTaskCompletion() | |
{ | |
PendingSimulatedTaskCallback task = pendingTasks_.front(); | |
pendingTasks_.pop_front(); | |
task.invokeCompletionCallback(); | |
} | |
class MyAsyncMethod { | |
typedef MyAsyncMethod this_t; | |
typedef void (this_t::*asyncmethod_fn_t) (); | |
// async method state | |
int i; | |
int waitCount; | |
#define BEGIN_ASYNC_METHOD switch (PC) { case 0:; | |
#define AWAIT_CALLBACK_PTR &async_callback_thunk_t<&this_t::async_method_fn<__LINE__> > | |
#define AWAIT {return; case __LINE__:;} // MUST be on same line as call | |
#define WAIT_TARGET_CALLBACK_PTR(x) &async_callback_thunk_t<&this_t::async_method_fn<-x> > | |
#define WAIT_TARGET(x) {return; case -x:;} | |
#define END_ASYNC_METHOD {return; default:;} } | |
template< asyncmethod_fn_t F > | |
static void async_callback_thunk_t( void *that ) | |
{ | |
(static_cast<this_t*>(that)->*F)(); | |
} | |
template<int PC> | |
void async_method_fn() { | |
BEGIN_ASYNC_METHOD | |
std::cout << "async method beginning" << std::endl; | |
initiateSimulatedTaskWithAsyncCallback(AWAIT_CALLBACK_PTR, this); AWAIT | |
std::cout << "before loop" << std::endl; | |
for(i=0; i < 5; ++i ){ | |
std::cout << "in loop " << i << std::endl; | |
initiateSimulatedTaskWithAsyncCallback(AWAIT_CALLBACK_PTR, this); AWAIT | |
} | |
std::cout << "after loop A" << std::endl; | |
initiateSimulatedTaskWithAsyncCallback(AWAIT_CALLBACK_PTR, this); AWAIT | |
std::cout << "after loop B" << std::endl; | |
std::cout << "before scatter-gather" << std::endl; | |
waitCount = 5; | |
for(int i=0; i<5;++i){ | |
initiateSimulatedTaskWithAsyncCallback(WAIT_TARGET_CALLBACK_PTR(1), this); | |
} | |
WAIT_TARGET(1) | |
std::cout << "received a scatter-gather callback" << std::endl; | |
if (--waitCount) { | |
return; // don't continue until all callbacks have been received | |
} | |
std::cout << "scatter-gather complete" << std::endl; | |
initiateSimulatedTaskWithAsyncCallback(AWAIT_CALLBACK_PTR, this); AWAIT | |
std::cout << "done" << std::endl; | |
END_ASYNC_METHOD | |
} | |
public: | |
void initiate() | |
{ | |
async_method_fn<0>(); | |
} | |
}; | |
int main(int argc, char* argv[]) | |
{ | |
std::cout << "*** AsyncMethod *** " << std::endl; | |
MyAsyncMethod async; | |
async.initiate(); | |
while (simulatedTaskIsPending()) | |
simulateAsyncTaskCompletion(); | |
std::cout << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment