1

I am bit confused as when do i need to pass packaged_task to std::async. Do i really need std::packaged_task when i can directly pass the function with arguments? Is there something which is possible only with packaged task and not with normal function approach?

Approach 1: std::async with lambda function

std::future<int> result= std::async(std::launch::async, [](int m, int n) { return m + n;} , 2, 4));

Approach 2: std::async with packaged_task,

        auto f = [](int m, int n) { return m + n;};
        std::packaged_task<int(int,int)> task(f);
        std::future<int> result = task.get_future();
     
        std::async(std::launch::async, std::move(task), 2, 4);
        int ans = result.get();
        

I have checked for answers but none of them gives me a proper use case. It looks like coder can just use any of these approaches BUT when does one scores over other?

bolov
  • 72,283
  • 15
  • 145
  • 224
Test
  • 564
  • 3
  • 12
  • 1
    My rule of thumb is: the more stuff put into a single statement, the higher the cognitive load. So I tend towards preferring code in smaller, easier to grasp sequential statements, rather than packing a lot of behavior into a single statement — because it is easier to code review and easier to maintain. I work with some brilliant developers who hold the opposing view, and would rather cram everything into one statement. The compiler doesn't care, and the optimizer can optimize either style really well. So use whichever works best for your team. – Eljay Jul 28 '21 at 12:33
  • @Eljay - Do you mean its just a question of preference and no other difference between approach 1 and 2? – Test Jul 28 '21 at 12:39
  • 1
    For `std::async` you should use lambdas. `std::packaged_task` is used without `std::async`. – bolov Jul 28 '21 at 12:39
  • @bolov - what do you mean when you say "the call to a packaged_task is async"? As far as i am aware , in order to run a packaged task asynchronously you need to call it via std::async. Calling packaged task without std::async amounts to a normal function call. – Test Jul 28 '21 at 12:42
  • @Test _"in order to run a packaged task asynchronously you need to call it via `std::async`"_ — I don't think so. Packaged tasks are used, for example, in thread pools, where you have a fixed number of threads and a shared queue of packaged tasks. Threads then just fetch tasks from the queue and execute them. No `async` is involved here. – Daniel Langr Jul 28 '21 at 12:44
  • @Test that was a mistake on my part. Edited the comment. – bolov Jul 28 '21 at 12:44

1 Answers1

3

You don't need std::packaged_task for std::async.

std::packaged_task is useful when you manage threads yourself but still need a callable wrapper with std::future. This means having own a worker thread or a thread pool implemented via std::thread or by other means.

std::packaged_task does other things related to asynchronous tasks:

  • std::future wrapping of the result
  • copying arguments when forwarding, instead of passign them by "universal reference"
  • ensuring move-only semantics instead of copyable (lambdas or std::function can be copied, std::packaged_task cannot)
Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
  • Can you please elaborate a bit more? I didn't fully understand your response as its too technical for me to understand in clear terms. What do you mean when you say "Manage thread yourself"? And what do you mean "but still want to have a part of task management to be done by the standard library"? – Test Jul 28 '21 at 12:49
  • 2
    elaborated a bit – Alex Guteniev Jul 28 '21 at 13:00