create_task и возвращаемые значения

Мне нужно вызвать метод Async в методе, который я объявил. Метод должен вернуть значение. Я пытаюсь превратить звонки в Магазин Windows в простой в использовании класс. Мой метод должен выглядеть так:

bool Purchase(enum_InAppOption optionToPurchase);

enum_InAppOption перечисление, состоящее из всех опций в приложении для покупки. В какой-то момент мне нужно позвонить RequestProductPurchaseAsync, Результат этого вызова определяет, должен ли метод возвращать trueили же false, Я новичок в c ++ / cx (или, по крайней мере, у меня длинная история с настоящего момента до последнего использования C ++), так что, может быть, это проще, чем я думаю.

create_task выглядит так:

create_task(CurrentAppSimulator::RequestProductPurchaseAsync(this->_LastProductId, false))

Варианты, которые я рассмотрел / попробовал:

  1. возврат задания не будет абстрагировать магазин

  2. попытался позвонить, ждать на задание. У меня есть исключение An invalid parameter was passed to a function that considers invalid parameters fatal.

  3. пытался использовать structured_task_group но, похоже, это не учитывает не возвращаемые пустые методы, или я пытаюсь дать неверную интерпретацию. Компилятор возвращает ошибку C2064 (погуглил, но не могу понять, что изменить)

  4. Используя массив задач и when_all

Нашел следующий код на http://msdn.microsoft.com/en-us/library/dd492427.aspx#when_all в середине страницы:

array<task<void>, 3> tasks =
{
create_task([] { wcout << L"Hello from taskA." << endl; }),
create_task([] { wcout << L"Hello from taskB." << endl; }),
create_task([] { wcout << L"Hello from taskC." << endl; })
};

auto joinTask = when_all(begin(tasks), end(tasks));

// Print a message from the joining thread.
wcout << L"Hello from the joining thread." << endl;

// Wait for the tasks to finish.
joinTask.wait();

Поэтому я попытался перевести его в следующий код:

array<task<Platform::String^>,1> tasks = {
create_task(CurrentAppSimulator::RequestProductPurchaseAsync(this->_LastProductId, false))
};

Несмотря на то, что я включил компилятор, выдает C2065 («массив»: необъявленный идентификатор), C2275 («Параллельность :: задача»<_ReturnType> ‘: незаконное использование этого типа в качестве выражения и некоторые ошибки, которые, по-видимому, являются ошибками после этих двух.

Подводя итог: Как заставить метод возвращаться после выполнения асинхронной задачи, чтобы я мог возвращать значимый результат, основываясь на асинхронной работе?

3

Решение

Как заставить метод возвращаться после выполнения асинхронной задачи, чтобы я мог вернуть значимый результат, основываясь на асинхронной работе?

Это не имеет большого смысла: «материал» не асинхронный если вы хотите дождаться его завершения, прежде чем вернуться. Это определение синхронный.

При использовании C ++ / CX вы не можете ждать невыполненной задачи на STA. Любая попытка сделать это приведет к исключению. Если вы собираетесь позвонить Purchase() на STA, и если он запускает асинхронную операцию, вы не можете дождаться завершения этой операции, прежде чем вернуться.

Вместо этого вы можете использовать .then выполнить другую операцию после завершения асинхронной операции. Если продолжение должно быть выполнено в вызывающем потоке, обязательно передайте use_current() контекст продолжения, чтобы гарантировать, что продолжение выполняется в правильном контексте.

2

Другие решения

Sascha,

  1. Возврат задачи приведет к абстрагированию хранилища, и я думаю, что это будет наиболее разумным решением, поскольку вы не ограничиваете пользователей своего вспомогательного класса в получении результатов сразу, но также позволяете им обрабатывать результаты по-своему. и асинхронно.
  2. Как правильно заметил @James, вам не разрешено ждать в потоке пользовательского интерфейса, тогда вы заставите приложение перестать отвечать, есть разные способы избежать ожидания:

    • создать продолжение с concurrency::task::then;
    • вы не можете ждать в потоке пользовательского интерфейса, но вы можете ждать завершения операции в потоке пользовательского интерфейса, это означает, что вы можете обернуть будущий результат задачи, выполняемой в пользовательском интерфейсе, в task_completion_event а затем дождаться события в другом (фоновом) потоке и обработать результат;

      concurrency::task_completion_event<Platform::String^> purchaseCompleted;
      
      create_task(CurrentAppSimulator::RequestProductPurchaseAsync(
      this->_LastProductId, false)).then(
      [purchaseCompleted](concurrency::task<Platform::String^> task)
      {
      try
      {
      purchaseCompleted.set(task.get());
      }
      catch(Platform::Exception^ exception)
      {
      purchaseCompleted.set_exception(exception);
      }
      });
      
      // and somewhere on non-UI thread you can do
      Platform::String^ purchaseResult = create_task(purchaseCompleted).get();
      
    • Вы можете достичь предыдущего трюка, используя больше средств, специфичных для WinRT, а не Concurrency Runtime, точнее, IAsyncOperation<T>::Completed а также IAsyncOperation<T>::GetResults;

  3. а также

  4. здесь кажется неуместным, так как у вас есть только одна реальная задача — совершить покупку.
1