Почему std::async вызывает функцию синхронно даже с указанным флагом std::launch ::async

#c #multithreading #asynchronous

#c #многопоточность #асинхронный

Вопрос:

Функция, которую я передаю std::async, печатает текущий идентификатор потока. Несмотря на вызов с флагом std::launch::async, он выводит тот же идентификатор ad. Это означает, что он вызывает функцию синхронно. Почему?

 void PrintThreadId()
{
    std::cout << std::this_thread::get_id() << std::endl;
}

int main()
{
    for (int i = 0; i < 5;   i)
    {
        auto f = std::async(std::launch::async, PrintThreadId);
        f.wait();
    }
}
  

Результат таков:
20936
20936
20936
20936
20936

Среда: VS 2015, W7.

Заранее благодарю вас!

Комментарии:

1. Возможно, стоит посмотреть, что делает f.wait() .

2. @Galik на самом деле для будущего, возвращаемого из async , не имеет значения, ожидает ли он явно

3. Проблема не в этом, но не используйте std::endl , если вам не нужны дополнительные функции, которые она выполняет. 'n' завершает строку.

Ответ №1:

Вы фактически сериализуете вызовы, ожидая каждого из них, таким образом, один и тот же поток может быть повторно использован без нарушения спецификации, согласно которой std::future выполняется потоком, отличным от потока вызывающего

Разбудите нас, когда следующий код покажет то же самое Caller ThreadId с остальными из них:

 void PrintThreadId()
{
    std::cout << std::this_thread::get_id() << std::endl;
}

int main()
{
    std::cout << "Caller threadId (to be different from any id of the future exec thread): ";
    PrintThreadId();

    for (int i = 0; i < 5;   i)
    {
        auto f = std::async(std::launch::async, PrintThreadId);
        f.wait();
    }
}
  

Комментарии:

1. Спасибо, один поток выполняет PrintTheadId() в main(), а другой выполняет PrintTheadId при вызове std::async без нарушения спецификации std::launch::async )

Ответ №2:

Время жизни вашего future заканчивается вместе с областью действия каждой итерации функции. Связанный с ним поток тоже умирает. Реализация может свободно использовать ее позже, т. Е. на следующей итерации вашего цикла.

Если вы измените код примера для печати текущего идентификатора потока, вы увидите, что текущий поток отличается:

 for (int i = 0; i < 5;   i)
{
    PrintThreadId();
    auto f = std::async(std::launch::async, PrintThreadId);
    f.wait();
}
  

живая демонстрация

Вы также должны учитывать, что возвращаемые фьючерсы async являются особыми — в деструкторе они блокируются до тех пор, пока задача не будет завершена. Больше информации в блоге Скотта Мейерса под противоположным заголовком: std::futures from std::async не являются особенными.