Разница между std :: обещанием lvalue и vvalue - PullRequest
0 голосов
/ 15 мая 2018

Насколько я понимаю, если мы вызываем метод get on future, полученный из обещания, тогда он будет ждать, пока вызов set_value, и, если он никогда не вызывается, программа будет ждать вечно, но каким-то образом это поведение не работает, когда я использую ссылку на обещание rvalue (этовыкидывает неисполненное обещание будущей ошибки), хотя то же самое работает со ссылкой на lvalue (ждать вечно).Есть ли основания для этого, потому что я считаю, что в случае ссылки на rvalue следует ждать вечно?

#include <iostream>
#include <future>
#include <thread>
#include <chrono>
void calculateValue(std::promise<int> &&p)
//void calculateValue(std::promise<int> &p) //uncomment this it will wait
{
  using namespace std::chrono_literals;

  std::cout<<"This is start of thread function "<<std::endl;
  //Do long operations
  std::this_thread::sleep_for(2s);
 // p.set_value(8);
  std::cout<<"This is end of thread function "<<std::endl;

}
int main() {

  std::promise<int> p;
  auto  fut = p.get_future();
  std::thread t(calculateValue,std::move(p));
  //uncomment this it will wait
  //std::thread t(calculateValue,std::ref(p);
  std::cout<<"main function ..."<<std::endl;
  std::cout<<"value is "<<fut.get()<<std::endl;
  t.join();
  return 0;

}

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Когда вы используете эту форму конструктора thread:

std::thread t(calculateValue, std::move(p));

затем изнутри p перемещается во временный объект std::promise. Это временное значение используется в качестве аргумента calculateValue независимо от типа аргумента:

void calculateValue(std::promise<int> &&p) // option #1
void calculateValue(std::promise<int> p)   // option #2

Перед тем, как поток завершит свое выполнение, временный объект (или параметр p во втором случае) уничтожается, и это вызывает std::future_error, так как общее состояние не готово (set_value не было вызвано).

Однако, если вы используете std::reference_wrapper:

std::thread t(calculateValue, std::ref(p));

тогда исходное обещание не перемещено, оно все еще существует, и его деструктор не вызывается до конца main. Что никогда не достигается, так как основной поток будет ждать на fut.get().


Итог: Проблема вовсе не связана с формой параметра calculateValue. Речь идет о том, переходите вы или нет из p во временное состояние, что, по сути, определяет, уничтожен ли деструктор обещания, связанного с будущим (и их общим состоянием).

0 голосов
/ 15 мая 2018

Когда вы делаете std::move(p), вы фактически отказываетесь от владения p потоку. Обещание p в функции main, так сказать, не имеет будущего.

Когда вы передаете ссылку (с std::ref), вы по-прежнему владеете обещанием, а функция потока просто имеет ссылку на обещание в вашей функции main. Это похоже на передачу указателя на переменную p.

По этой причине ваша программа не сможет ждать при перемещении обещания, но ждет, как и при передаче ссылки.

...