2

I've seen create_task used in a couple ways:

void Bob()
{
    create_task() { /* do stuff */ }.then([](){ /* do more stuff */ });
}

and

task<void> Bob()
{
    return create_task() { /* do stuff */ }.then([](){ /* do more stuff */ });
}

Why bother returning the task (in the second example) when asynchronous behavior can be achieved with either approach?

Clarification: I'm not asking about the void return type specifically. It could be an int, object, or something else.

phonetagger
  • 7,701
  • 3
  • 31
  • 55
Craig
  • 1,890
  • 1
  • 26
  • 44
  • 1
    It's unclear what you are asking. – R Sahu Apr 10 '18 at 15:28
  • 1
    @R Sahu - Not sure how it's unclear; I'm asking when one would return a task object when it seems unnecessary to achieve asynchronous behavior. I've reworded the question to clarify this point. – Craig Apr 10 '18 at 15:38
  • It's unclear to me because there is no explanation of what `task` is and how it is used in your application. – R Sahu Apr 10 '18 at 15:41
  • This article, [Implementing the Task-based Asynchronous Pattern](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/implementing-the-task-based-asynchronous-pattern) has a discussion that may be helpful. – Richard Chambers Apr 10 '18 at 15:42
  • 1
    Are you specifically asking about the case where the task has a void return type? Because it's obvious that if the task returns a value, you need the task object to get out the value. If not it could still be useful for checking if the task has completed. – Sean Burton Apr 10 '18 at 15:44
  • 5
    @RSahu the question is very clear especially with the tags specified. Its a bit opinion oriented however the core question is what are the pros and cons of the two approaches. – Richard Chambers Apr 10 '18 at 15:44
  • @Sean Burton - "...it could still be useful for checking if the task has completed" - I think that's what I was looking for. – Craig Apr 10 '18 at 15:48
  • @SeanBurton it would seem that the `Task` object could also be used for further continuations as well? – Richard Chambers Apr 10 '18 at 16:03

1 Answers1

3

void/task<void> is a special case here, because you can magic a void from nowhere. You couldn't do the same with a int, std::string or similar.

void Bob()
{
    create_task() { /* do stuff */ }.then([](){ /* do more stuff */ });
}

After this has returned /* do stuff */ and /* do more stuff */ have started, and any handle on their progress is discarded.

task<void> Bob()
{
    return create_task() { /* do stuff */ }.then([](){ /* do more stuff */ });
}

After this has returned /* do stuff */ and /* do more stuff */ have started, and you have a handle to wait for them to finish.

int Alice()
{
    return create_task() { /* do stuff */ }.then([](){ /* do more stuff */ return 42; }).get();
}

After this has returned /* do stuff */ and /* do more stuff */ have finished, with a final result available.

task<int> Alice()
{
    return create_task() { /* do stuff */ }.then([](){ /* do more stuff */ return 42; });
}

After this has returned /* do stuff */ and /* do more stuff */ have started, and you have a handle to wait for them to finish, and get the result.

Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Thanks, Caleth. Can you add to your answer an example of using the handle to wait for the finish & get the result? – phonetagger Apr 10 '18 at 16:18
  • See also [Task Parallelism (Concurrency Runtime)](https://msdn.microsoft.com/en-us/library/windows/desktop/dd492427(v=vs.120).aspx) – Richard Chambers Apr 10 '18 at 16:19
  • @phonetagger the examples in [Composing Tasks](https://msdn.microsoft.com/en-us/library/windows/desktop/dd492427(v=vs.120).aspx#composing_tasks) are common patterns, starting multiple tasks then proceeding when they are done – Caleth Apr 10 '18 at 16:24
  • See as well [How to return value from nested task in c++/cx?](https://stackoverflow.com/questions/33323277/how-to-return-value-from-nested-task-in-c-cx) – Richard Chambers Apr 10 '18 at 16:27