1

Я пытаюсь отменить операцию, написанную на C++/CX из C#. Несмотря на то, что я написал оба фрагмента кода, я не могу заставить операцию нормально отменить, ожидая ее со стороны C#. Вот пример:Как отменить операцию async в C++/CX с C#

От C#:

var tcs = new CancellationTokenSource(); 
tcs.Cancel(); 
var class1 = new MyClass(); 
try 
{ 
    var asyncOp = await class1.DoSomeTaskAsync().AsTask(tcs.Token); 
} 
catch (OperationCanceledException oce) 
{ 
    //I want to get here 
    Handle(oce); 
} 

От C++:

IAsyncOperation<bool>^ MyClass::DoSomeTaskAsync(){ 
     return concurrency::create_async([](concurrency::cancellation_token ct) { 
      task<bool> my_task([]() { 
       doSomething1(); 
       if (concurrency::is_task_cancellation_requested()) 
       { 
        concurrency::cancel_current_task(); 
       } 
       doSomething2(); 
       return false; 
      }, ct); 
      return my_task; 
     }); 
    } 

Проблема, кажется, что проходит в маркере в метод расширения AsTask ничего не делает при вызове задачи по ABI. При отладке стороны C++ функция ct и is_task_cancellation_requested() указывает, что отмена не была запрошена.

+0

Вызов 'txw.Cancel' после запуска операции async. Убедитесь, что ваша операция достаточно длительная, чтобы ее отменить и спросить несколько раз, если задача была отменена. – kiewic

+0

Я не уверен, почему это требование, чтобы отменить задачу _after_, она была запущена. Что касается состояния, при котором вы переходите на страницу, на странице запускается ряд задач, которые, в свою очередь, запускают ряд задач, а затем вы быстро перемещаетесь от страницы. Могут быть некоторые задачи, которые еще предстоит запустить, которые вы хотите немедленно отменить, не так ли? – Kellen

+0

Итак, вы можете добавить логическое значение, чтобы указать, что вы решили пойти куда-то еще, чтобы вы не запускали другую операцию async. Моя ** догадка ** заключается в том, что только токены, созданные перед вызовом 'Cancel', будут отменены. Итак, если вы запустили операцию async с цепочкой после вызова 'Cancel', она будет отменена, пока токен был сгенерирован перед вызовом' Cancel'. – kiewic

ответ

2

Попробуйте это. В C++ Windows Runtime Component выполните что-то, что занимает много времени, например, concurrency::wait(2000) будет спать поток в течение двух секунд (не делайте этого в реальном приложении).

#include <ppltasks.h> 

using namespace Windows::Foundation; 

IAsyncOperation<bool>^ MyClass::DoSomeTaskAsync() 
{ 
    return concurrency::create_async([=](concurrency::cancellation_token token) 
    { 
     // Do something. 
     concurrency::wait(2000); 

     if (concurrency::is_task_cancellation_requested()) 
     { 
      concurrency::cancel_current_task(); 
     } 

     // Do something else. 
     concurrency::wait(2000); 

     return true; 
    }); 
} 

Тогда в вашем C# Windows Store App создать две кнопки:

<Button x:Name="DoButton" Click="DoButton_Click">Do</Button> 
<Button x:Name="CancelButton" Click="CancelButton_Click">Cancel</Button> 

новости Звоните асинхронный метод вашего компонента в Do кнопку.

private System.Threading.CancellationTokenSource cts; 

private async void DoButton_Click(object sender, RoutedEventArgs e) 
{ 
    cts = new System.Threading.CancellationTokenSource(); 
    var class1 = new MyClass(); 
    try 
    { 
     var asyncOp = await class1.DoSomeTaskAsync().AsTask(cts.Token); 
     System.Diagnostics.Debug.WriteLine(asyncOp); 
    } 
    catch (OperationCanceledException oce) 
    { 
     // I want to get here. 
     System.Diagnostics.Debug.WriteLine(oce); 
    } 
} 

И отменить операцию в Отмена кнопку.

private void CancelButton_Click(object sender, RoutedEventArgs e) 
{ 
    cts.Cancel(); 
    cts = null; 
} 

Запустите приложение, нажмите кнопку Do и в течение двух секунд нажмите кнопку Cancel. Вы должны получить System.Threading.OperationCanceledException.