【问题标题】:How to stop a call resulting in IAsyncOperation?如何停止导致 IAsyncOperation 的呼叫?
【发布时间】:2017-05-11 21:26:27
【问题描述】:

在我的应用程序中,我通知了多个设备。如果设备无法连接并且在几秒钟内没有响应,我想取消通话。

我的代码是:
await characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync (GattClientCharacteristicConfigurationDescriptorValue.Notify);

现在经过一些研究,我发现通常可以通过 CancelationToken (_ct) 并执行以下操作:

首先创建一个包含调用的操作:
IAsyncOperation<GattCommunicationStatus> operation = characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync (GattClientCharacteristicConfigurationDescriptorValue.Notify);

然后使用 CancellationToken 创建一个任务:
Task&lt;GattCommunicationStatus&gt; task = operation.AsTask(_ct);

然后等待它:
GattCommunicationStatus status = await task;

现在,即使 CancellationTokenIsCancellationRequested-属性设置为 true,情况也是如此。通话不会停止。
而且,设备已经在第一行之后得到Notified!这不应该在调用await之后发生吗??

我在使用令牌时犯了错误还是这是更大的事情?

编辑
在与@Andrii Litvinov 交谈后,我在我对问题的初始描述中添加了更多代码。这是整个方法:

public async Task<GattCommunicationStatus> NotifyDevice(DeviceInformationDisplay deviceInfo, CancellationToken _ct)
        {
            try
            {
                BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
                service = device.GetGattService(new Guid(Service_UUID));
                characteristic0 = service.GetCharacteristics(new Guid(Characteristic_0_UUID)).First();

                characteristic0.ValueChanged += characteristic0ValueChanged;
                GattCommunicationStatus status = await characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                _ct.Register(() =>
                {
                // trying to cancel the operation somehow
                });
                IAsyncOperation<GattCommunicationStatus> operation = characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                Task<GattCommunicationStatus> task = operation.AsTask(_ct);
                GattCommunicationStatus status_1 = await task;

                if (!elapsedTimeWatcher.IsRunning)
                {
                    elapsedTimeWatcher.Start();
                }

                else
                {
                    elapsedTimeWatcher.Restart();
                }
                return status;
            }
            catch(OperationCanceledException e)
            {
                return GattCommunicationStatus.Unreachable;
            }
            catch (Exception e)
            {
                return GattCommunicationStatus.Unreachable;
            }

        }

【问题讨论】:

  • 取消是合作的。要取消的操作需要了解取消令牌并观察取消请求。如果长时间运行的操作没有接受取消令牌的重载,则仅在其附近放置一个不会做任何事情。
  • 所以您是说如果WriteClientCharacteristicConfigurationDescriptorAsync 没有带有CancellationToken 的重载,添加AsTask,不会改变任何东西吗?那么有没有办法取消这个调用呢?
  • 看起来不像。
  • 有没有办法杀死它?以不合作的方式?
  • 你试过关闭operation.Close() 的方法吗?您可以模拟需要较长时间并且可以取消的操作吗?当您在await task 中等待时,看起来操作已经完成。

标签: c# asynchronous bluetooth-lowenergy iasyncoperation


【解决方案1】:

基于docs,您做得对:

try
{
...

IAsyncOperation<GattCommunicationStatus> operation =
    characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync(
        GattClientCharacteristicConfigurationDescriptorValue.Notify);
return await operation.AsTask(_ct);

...
}
...

此代码应注册到令牌并在后台调用operation.Cancel()

您能否将令牌设置为较低的值以查看操作是否实际被取消?执行该方法通常需要多长时间?

试试:

CancellationTokenSource cts = new CancellationTokenSource(10);
await NotifyDevice(BLEDevice, cts.Token);

甚至更低的值。

【讨论】:

  • 这很奇怪!从这一行 op = characteristic0.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify); 到这一行:Task&lt;GattCommunicationStatus&gt; task = op.AsTask(cts.Token); 需要 7 (!!) 秒...
  • 好的,可能是因为在设备回复之前无法取消操作或发生内部超时。我想7秒后它将成功取消。并且可以与另一个答案的解决方案一起正常工作。如果它阻止了 UI,您可以考虑使用 Task.Run 运行它。
  • 是的,我想是的,我将再次使用另一种方法并尝试使任务正常工作。非常感谢!
  • 不客气。如果任何答案可以帮助您解决问题,请考虑接受这些答案。
猜你喜欢
  • 2014-02-01
  • 2012-03-11
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
相关资源
最近更新 更多