0
votes

I was reading abut std::async with std::launch::async and read that with that policy, the callable will be called in a new thread.

So for sake of test, I did as follow:

struct Wrapper
    {   
        void consume()
        {
             std::cout << "consume " << std::this_thread::get_id() << std::endl;
            std::for_each(arr.begin(), arr.end(), [](int val) {std::cout << val; });
        }

        bool produce()
        {
            std::cout << "produce " << std::this_thread::get_id() << std::endl;

            arr = { 1,0,3 };
            return true;
        }
    };


    int main()
    {

        std::cout << "main " << std::this_thread::get_id() << std::endl;

        Wrapper wrap;
        std::future<bool> fut = std::async(std::launch::async, &Wrapper::produce, &wrap);

        if (fut.get())
            std::async(std::launch::async, &Wrapper::consume, &wrap);

    }

So based on that, I will excpect 3 threads :

  • thread 1 : the main thread
  • thread 2 : the first call of std::async (executing the produce fct)
  • thread 3 : the second call of std::async (executing the consume fct)

when I run the program i got :

enter image description here

Why is the two calls of the std::async have the same thread ID ??

Thank you.

1
The implementation is allowed to use a thread pool. Creating new threads is very expensive, a thread pool spreads this cost over all the async tasks. - Richard Critten
So behind the scene there were 3 distincts thread, but as you mentionned, we used a thread pool resulting on the same ID. - Blood-HaZaRd
produce and consume are not executed concurrently. consume is called when produce finished. So these functions can be executed by the same thread. Call your code concurrently and you see two different IDs. - rafix07
Also, I think thread ID's can be recycled so the fact that you have identical thread ID's does not actually mean you have the same thread. (Many implementations do avoid recycling thread ID's, but that is a Quality of Implementation thing.) - MSalters
@Blood-HaZaRd: You misunderstand. You say "same thread because same ID". That is wrong. I pointed out that you could have "same ID despite different threads". Therefore, your conclusion is wrong. (does not follow from the premise) - MSalters

1 Answers

2
votes

The standard says about std::async :

If launch​::​async is set in policy, calls INVOKE(DECAY_­COPY(std​::​forward<F>(f)), DECAY_­COPY(std​::​forward<Args>(args))...) as if in a new thread of execution [...]

Link

The important part is "as if in a new thread of execution". The implementation must behave as if the callable object was called from a new thread, but it's not required to actually run on a new thread. This leeway is provided so that the standard library implementer can reuse the same threads, perhaps by keeping a handy pool of threads on standby (a threadpool pattern), which can be more responsive than creating and destroying threats for every call to std::async. Though in theory an implementation could also choose to create and destroy threads each time, or do anything else that respects the requirements of the standard.