У меня есть пример кода. Я передаю launch::async в async, поэтому я ожидаю, что лямбда-функция будет вызвана немедленно, но этого не произойдет.
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <chrono>
#include <string>
using namespace std;
mutex m;
void print(string s)
{
lock_guard<mutex> l(m);
cout << s << endl;
}
int main() {
print("main thread1");
std::future<int> f = std::async(launch::async, [](){
print("async");
return 1;
});
print("main thread2");
int i = f.get();
print("main thread3");
return 0;
}
Результат, которого я ожидаю, будет следующим:
main thread1 async main thread2 main thread3
Но реальный результат выглядит так:
main thread1 main thread2 async main thread3
Не могли бы вы объяснить, почему лямбда вызывается только при вызове будущего get()?
Если я поставлю sleep_for перед main thread2, то это будет то, чего я ожидал.





Вызов async возвращается, как только новый поток становится созданный. Теперь у вас есть два отдельных потока, и единственная корреляция между операциями в этих двух потоках состоит в том, что поток, созданный вызовом async, должен быть завершен до того, как вызов f.get() вернется. Итак, поведение, которое вы видите, соответствует требованиям. Ожидаемое поведение также соответствует требованиям. В этом суть запуска отдельных потоков: они работают независимо, пока вы не сделаете что-нибудь для их синхронизации.
Итак, если я понимаю, что лямбда вызывается как можно скорее, а позже возвращаемые данные извлекаются из второго потока? Значит, утверждение «лямбда запускается только при вызове get()» неверно?
Функция потока вызывается всякий раз, когда к ней обращается планировщик потоков. Если поток не завершился (вызовом и возвратом из функции потока) в то время, когда вызывается get(), вызов get() блокируется до завершения потока.
Ваше ожидание показывает, что вы действительно не понимаете, что такое асинхронность. Давайте посмотрим на следующий алгоритм:
operation1
asynchronous operation2
operation3
Здесь операция1 выполняется до того, как будет выполнен асинхронный вызов операции2. Когда операция2 вызывается асинхронно, создается новый поток, и его конец не ожидается. Если операция3 ожидает, что операция2 уже будет выполнена, то это ошибка в коде. Если вам нужен результат данного потока, вам нужно будет с ним синхронизироваться.
Спасибо за ответ. Да я понимаю о чем ты. Так почему же, когда я отлаживаю код и устанавливаю точку останова на get() и во время выполнения этой строки начинает выполняться лямбда? Разве get() не должен только извлекать данные, а не запускать лямбда-выражение?
@drewpol, потому что поток, открытый асинхронно, выполняется, пока вы смотрите на код. Мы, люди, слишком медлительны для подобных вещей.
Попробуй это:
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <chrono>
#include <string>
using namespace std;
using namespace std::chrono;
mutex m;
void print(string s)
{
lock_guard<mutex> l(m);
nanoseconds ms = duration_cast< nanoseconds >(
system_clock::now().time_since_epoch()
);
cout << s << "(" << ms.count() << ")" << endl;
}
int main() {
print("main thread1");
future<int> f = async(launch::async, [](){
print("async");
return 1;
});
//this_thread::sleep_for(2s);
print("main thread2");
int i = f.get();
print("main thread3");
return 0;
}
Попробуйте поэкспериментировать с функцией сна (this_thread::sleep_for(2s);), чтобы понять, что произошло.
Если вы хотите видеть «async» перед «main thread2» - установите этот спящий режим прямо перед вызовом функции print.
Создание потоков - очень сложная задача для любой платформы и ОС, на это уходит много наносекунд, в то время как просто вывод чего-либо - гораздо более быстрая задача. Таким образом, вы даже можете добавить еще 10 вызовов print - они будут быстрее, чем печать внутри нового потока.
Но f.get() в вашем коде заставляет систему ждать результата. Работает как сон. Итак, это единственная причина, по которой «основной поток3» печатается последним в вашем примере кода.
Я получаю вывод с помощью этого кода:
./a.out
main thread1(1534603161902827214)
main thread2(1534603161902924375)
async(1534603161902977095)
main thread3(1534603161903114658)
Разница между «основным потоком1» и «основным потоком2» составляет 97161. И разница между 'main thread2' и 'main thread3' составляет 190283. Все выходы находятся в одном потоке, шаг за шагом. Но этот f.get() тормозит последний звонок.
Другой момент. C++ - очень сложный язык, и педантичный синтаксис - ваш помощник в борьбе с ошибками в коде. Здесь вы используете using namespace std;, но все равно пишете пространство имен std::. Это стилистическая ошибка.
Лямбда называется асинхронно. Он может быть вызван до, после или одновременно с любой частью
mainмежду вызовамиstd::asyncиstd::future::get.