Generic async task wrapper
This topic provides an example of a generic async task wrapper. Instead of manually setting up async blocks and calling XAsyncRun
for each task, create a RunTask
wrapper to simplify this
process. By using this wrapper, you can specific a task queue, a work, and an optional completion callback.
void RunTask(XTaskQueueHandle taskQueue,
std::function<void()> workCallback,
std::function<void()> completionCallback)
{
struct RunTaskContext
{
std::function<void()> workCallback;
std::function<void()> completionCallback;
};
RunTaskContext* context = new RunTaskContext();
context->workCallback = workCallback;
context->completionCallback = completionCallback;
XAsyncBlock* async = new XAsyncBlock{};
async->queue = taskQueue;
async->context = context;
async->callback = [](XAsyncBlock* async)
{
RunTaskContext* context = static_cast<RunTaskContext*>(async->context);
context->completionCallback();
delete context;
delete async;
};
// Callback passed to XAsyncRun is the work callback
XAsyncRun(async,
[](XAsyncBlock* async)->HRESULT
{
RunTaskContext* context = static_cast<RunTaskContext*>(async->context);
context->workCallback();
return S_OK;
});
}
The previous sample implements a function that takes an async block and two callbacks: one work and one completion. You can write a version to just take a work callback, because the completion callback is optional.
It uses the standard pattern to setup an async block, setup context
data, and call XAsyncRun. RunTask
encapsulates the boilerplate
code, creating a simple standalone task function. Simple data capturing passes to the callbacks without context parameters by using std::function
.
RunTask(taskQueue,
[]()
{
// Work Callback
},
[]()
{
// Completion Callback
});