patterncppMinor
Continuation Implementation in C++11
Viewed 0 times
implementationcontinuationstackoverflow
Problem
While playing with the concurrency features in C++11 I noticed that there wasn't any support for continuations. I wanted to develop something similar to Tasks in The Parallel Patterns Library (PPL), where a Task can run asynchronously and execute a continuation upon completion using the 'then' member function.
I designed my class around
I have two types of continuations, one for when the asynchronous operation produces a result and one for when it doesn't. Both implement an interface that specifies the API for the
```
class IContinuation
{
public:
IContinuation(){
I designed my class around
std::future and std::async, which provides the asynchronous processing. The function to run asynchronously accepts any number of parameters and is called using std::async:template
class FutureWithContinuations final
{
public:
typedef std::function ContinautionSignature;
template
FutureWithContinuations(Function&& futureFunction, ArgTypes&&... args)
: m_continuations()
, m_future()
{
// Let the concurrency runtime decide whether to run asynchronously or to defer running of the future
auto future = std::async(std::launch::any, std::forward(futureFunction), std::forward(args)...);
m_future = future.share();
}
template
void then(const Function& continuationFunction)
{
auto continuation = make_unique_continuation(continuationFunction, m_future);
m_continuations.push_back(std::move(continuation));
}
void wait()
{
if (!m_future.valid())
throw std::future_error(std::future_errc::no_state);
m_future.wait();
for (const auto& continuation : m_continuations)
{
continuation->execute();
}
m_continuations.clear();
}
T get()
{
return m_future.get();
}
private:
std::vector> m_continuations;
std::shared_future m_future;
};I have two types of continuations, one for when the asynchronous operation produces a result and one for when it doesn't. Both implement an interface that specifies the API for the
FutureAndContinuations class to use when dealing with continuations:```
class IContinuation
{
public:
IContinuation(){
Solution
Not sure what kind of feedback you're looking for here.
What you've implemented is not equivalent to what's usually called
What you've got, on the other hand, allows you to do something like
I don't really understand why you'd want the latter semantics. Do you find them useful?
You misspelled "ContinuationSignature" here; but it doesn't matter, because the type is unused. Remove it.
Your class
If you do this, about half of your code simply disappears!
(You'll still need to specialize and/or overload the above function a little bit to deal with
You may already be aware that in C++14, with proper library support, you can rewrite
What you've implemented is not equivalent to what's usually called
.then(). The usual semantics of .then() allow you to do things likestd::future f = std::async([]{ return 1; });
std::future g = f.then([](std::future x){ return x.get() + 1; });
int v = g.get();
assert(v == 1+1);What you've got, on the other hand, allows you to do something like
std::future f = std::async([]{ return 1; });
f.then([](int x){ printf("%d\n", x); return x + 1; });
int v = f.get(); // prints "1"
assert(v == 1); // v is not 2I don't really understand why you'd want the latter semantics. Do you find them useful?
typedef std::function ContinautionSignature;You misspelled "ContinuationSignature" here; but it doesn't matter, because the type is unused. Remove it.
Your class
Continuation is merely a type-erased wrapper around a callable. We have a name for that in C++11 and later: it's called std::function. Consider:template
std::function make_unique_continuation(
const ContinuationFunction& continuationFunction,
const std::shared_future& sharedFuture)
{
return [=]() mutable { continuationFunction(sharedFuture.get()); };
}If you do this, about half of your code simply disappears!
(You'll still need to specialize and/or overload the above function a little bit to deal with
void, but it looks like you've got the right ideas about that already.)You may already be aware that in C++14, with proper library support, you can rewrite
typename std::enable_if::value>::type as simply std::enable_if_t>.Code Snippets
std::future<int> f = std::async([]{ return 1; });
std::future<int> g = f.then([](std::future<int> x){ return x.get() + 1; });
int v = g.get();
assert(v == 1+1);std::future<int> f = std::async([]{ return 1; });
f.then([](int x){ printf("%d\n", x); return x + 1; });
int v = f.get(); // prints "1"
assert(v == 1); // v is not 2typedef std::function<void(T)> ContinautionSignature;template<typename FutureReturnType, typename ContinuationFunction>
std::function<void()> make_unique_continuation(
const ContinuationFunction& continuationFunction,
const std::shared_future<FutureReturnType>& sharedFuture)
{
return [=]() mutable { continuationFunction(sharedFuture.get()); };
}Context
StackExchange Code Review Q#91269, answer score: 2
Revisions (0)
No revisions yet.