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);
Что мне здесь не хватает?
Ответы
Ответ 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.