Подтвердить что ты не робот

Std:: async не будет порождать новый поток, когда возвращаемое значение не сохраняется

Считаю, что у меня есть lamba foo, который просто делает что-то, и ничего не нужно возвращать. Когда я это сделаю:

std::future<T> handle = std::async(std::launch::async, foo, arg1, arg2);

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

std::async(std::launch::async, foo, arg1, arg2);

Что мне здесь не хватает?

4b9b3361

Ответ 1

От just::thread документация:

Если политика std::launch::async, тогда выполняется INVOKE(fff,xyz...) в своем потоке. Возвращенный std::future будет готов, когда этот поток будет завершен, и будет содержать либо возвращаемое значение, либо исключение, вызванное вызовом функции. Деструктор последнего будущего объекта, связанного с асинхронным состоянием возвращаемого std::future, должен блокироваться до тех пор, пока будущее не будет готово.

В

std::async(std::launch::async, foo, arg1, arg2);

Возвращенное будущее не назначается нигде, а блоки его деструктора до тех пор, пока foo не закончится.

Ответ 2

Я хотел бы добавить ссылку на статью Херба Саттера на async и ~ future, в которой он утверждает, что фьючерсы никогда не должны блокироваться.

Ответ 3

Почему блокировка?

  • std::async(); возвращает std::future временный объект
  • временный объект немедленно уничтожается, вызывая desctructor.
  • std::future Деструктор блокируется. Это плохо и хлопотно.

Почему присваивание в порядке?

При назначении переменной возвращенный объект не будет немедленно уничтожен, но позже, до конца области вашего кода вызова.

Пример кода: main1 в порядке. main2 и main3 эквивалентно блокируют основной поток.

void forever() {
    while (true);
}

void main1() {
    std::future<void> p = std::async(std::launch::async, forever);
    std::cout << "printing" << std::endl; // can print, then forever blocking
}

void main2() {
    std::async(std::launch::async, forever);
    std::cout << "printing" << std::endl; // forever blocking first, cannot print
}

void main3() {
    {std::future<void> p = std::async(std::launch::async, forever);}
    std::cout << "printing" << std::endl; // forever blocking first, cannot print
}

Взгляните на cplusplus.com

Возвращаемое значение std:: async Когда выбран запуск:: async, возвращаемое будущее связано с конец созданного потока, даже если его общее состояние никогда не доступно: в этом случае его деструктор синхронизируется с возвратом fn. Следовательно, возвращаемое значение не должно игнорироваться для асинхронных поведение, даже когда fn возвращает void.