Programming with Tasks

All long running or potentially blocking APIs in Casablanca are asynchronous, for example any API which makes a call going across a network. PPL tasks are used to represent the completion of some asynchronous work. In order to make Casablanca usable also with Visual Studio 2010 and on other non Windows platforms, we have built a special version of PPL tasks and included it in the Casablanca release. In order for it peacefully co-exist with PPL, we placed the special version in a different namespace, “pplx.”

A task represents an operation that may or may not have finished once a function producing it returns. For example, when sending an HTTP message, we will eventually get a response message back. A task represents this eventually available response:

web::http::client::http_client client(U("http://localhost:80"));
pplx::task<web::http::http_response> resp = client.request(web::http::methods::GET, U("/foo.html"));

Here, the ‘resp’ task provides us a placeholder for a value that will be available in the future.

Once you have a task, you need to (eventually) get a value out of it. Since it is possible that the operation finishes so fast that the value is available immediately, it may be reasonable to ask the task whether it is “done” or not:

bool done = resp.is_done(); 

If this function returns true, the value can be retrieved using ‘get(),’ which is guaranteed not to block when ‘is_done()’ returned true:

web::http::http_response response = resp.get(); 

If ‘is_done()’ returns false, calling ‘get()’ will risk blocking the thread, which defeats the purpose of using an asynchronous API in the first place (it will keep GUIs from refreshing and servers from scaling). For this situation, we need to take a different approach: attach a handler function to the task, which will be invoked once the task completes. We do this using the ‘then()’ function:

resp.then([=] (web::http::http_response  response)

The function object passed to then() of a task<T> should take an argument either of type T or task<T>, the latter being the only way to observe exceptions raised by the operation – a call to get() inside the response handler will re-throw any exception that resulted from the operation. Thus, the following example also works, but it also allows exceptions to be seen and handled:

resp.then([=](pplx::task<web::http::http_response> task)
    web::http::http_response  response = task.get();

Since we know the task has finished, calling ‘get()’ inside the callback function object is never going to block.

More information on PPL tasks is available on MSDN, including information on how to wait for more than one task with a single call.

Last edited Sep 19, 2014 at 11:22 PM by stevetgates, version 16