Задача запланирована и ожидает выполнения, но никогда не выполняется - PullRequest
0 голосов
/ 27 сентября 2019

Я новичок в асинхронном программировании на C #, и у меня возникли проблемы с некоторыми асинхронными методами.Эти методы взаимодействуют с внешним датчиком движения Bluetooth.Проблема в том, что в некоторых редких случаях один и тот же метод ожидает задачу, которая никогда не запускается.

Ситуация на изображении ниже.Задача MBientLab.MetaWear.Impl.MetaWearBoard.createRouteAsync () ожидает завершения запланированной задачи.Таким образом, эта задача должна быть запущена из задачи MBientLab.MetaWear.Impl.MetaWearBoard.createRouteAsync () , которая является частью используемого API.

Currently running tasks

Итак, как мы видим, выделенная строка является задачей, которая запланирована и ожидает выполнения, но она остается в этом состоянии независимо от того, как долго я буду ждать.Он никогда не входит в активное состояние.Другие задачи ожидают завершения выделенной задачи, поэтому все застряло.

Может ли это быть тупиком или это может быть задача, ожидающая чего-то, что никогда не завершится?Я немного запутался и не знаю, как решить эту проблему.

РЕДАКТИРОВАТЬ: Я извлек код, который вызывает проблемы.Для работы нужны самородки из , использующие операторы , Windows SDK и датчик.Так что вы, вероятно, не сможете его запустить, но, возможно, есть некоторые очевидные ошибки.

// Nuggets
using MbientLab.MetaWear;
using MbientLab.MetaWear.Core;
using MbientLab.MetaWear.Data;
using MbientLab.MetaWear.Sensor;
using MbientLab.MetaWear.Win10;

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;

namespace MBientLabSensor
{
    public class MotionSensor
    {
        public List<double> GetX { get; } = new List<double>();
        public List<double> GetY { get; } = new List<double>();
        public List<double> GetZ { get; } = new List<double>();

        IMetaWearBoard _metawearDevice = null;

        // List of Bluetooth devices found after scanning
        private List<BluetoothLEDevice> DeviceList = new List<BluetoothLEDevice>();

        public async Task Connect(string MAC, int retries = 1)
        {
            if (_metawearDevice != null)
            {
                await StopAndDisconnectMotionSensor();
            }

            await ConnectToSensor(MAC.Trim(), retries);
        }

        public async Task StopAndDisconnectMotionSensor()
        {
            StopAccelerometer(_metawearDevice);
            await Disconnect(_metawearDevice);
        }

        public void StopAccelerometer(IMetaWearBoard _metawearDevice)
        {
            if (_metawearDevice == null)
            {
                throw new ArgumentNullException("The provided device is null!");
            }

            var acc = _metawearDevice.GetModule<IAccelerometer>();
            // Put accelerometer back into standby mode
            acc.Stop();
            // Stop accelerationi data
            acc.Acceleration.Stop();
        }

        public async virtual Task Disconnect(IMetaWearBoard _metawearDevice)
        {
            if (_metawearDevice == null)
            {
                throw new ArgumentNullException("The MetaWear device instance is null!");
            }

            _metawearDevice.TearDown();

            // Have the board terminate the BLE connection
            await _metawearDevice.GetModule<IDebug>().DisconnectAsync();
        }

        public async Task ConnectToSensor(string MAC, int retries = 3)
        {
            BluetoothLEDevice device = DeviceList.Find(x => ConvertToMAC(x.BluetoothAddress).Trim() == MAC.Trim());
            await AttemptConnect(device, retries);
        }

        private async Task AttemptConnect(BluetoothLEDevice BLEDevice, int retries)
        {
            _metawearDevice = await ConnectToDevice(BLEDevice, retries);

            if (_metawearDevice != null)
            {
                Task task = Task.Run(async () => await Setup(_metawearDevice));
                SetAccSamplingRate(_metawearDevice, 100f, 16f);
                StartAcc(_metawearDevice);
            }
        }

        public async Task Setup(IMetaWearBoard device, float connInterval = 7.5f)
        {
            if (device == null)
            {
                throw new ArgumentNullException("The provided device is null!");
            }

            // Set the connection interval
            await SetBLEConnectionInterval(device, connInterval);
            var acc = device.GetModule<IAccelerometer>();

            // Use data route framework to tell the MetaMotion to stream accelerometer data to the host device
            await acc.Acceleration.AddRouteAsync(source => source.Stream(data =>
            {
                // Clear buffers if there is too much data inside them
                if (GetX.Count > 1000)
                {
                    ClearSensorData();
                }

                // Buffer received data
                GetX.Add(data.Value<Acceleration>().X);
                GetY.Add(data.Value<Acceleration>().Y);
                GetZ.Add(data.Value<Acceleration>().Z);
            }));
        }

        public void ClearSensorData()
        {
            GetX.Clear();
            GetY.Clear();
            GetZ.Clear();
        }

        private async Task SetBLEConnectionInterval(IMetaWearBoard device, float maxConnInterval = 7.5f)
        {
            if (device == null)
            {
                throw new ArgumentNullException("The provided device is null!");
            }

            // Adjust the max connection interval
            device.GetModule<ISettings>()?.EditBleConnParams(maxConnInterval: maxConnInterval);
            await Task.Delay(1500);
        }

        public void SetAccSamplingRate(IMetaWearBoard device, float samplingRate = 100f, float dataRange = 16f)
        {
            if (device == null)
            {
                throw new ArgumentNullException("The provided device is null!");
            }

            var acc = device.GetModule<IAccelerometer>();
            // Set the data rate and data to the specified values or closest valid values
            acc.Configure(odr: samplingRate, range: dataRange);
        }

        public void StartAcc(IMetaWearBoard device)
        {
            if (device == null)
            {
                throw new ArgumentNullException("The provided device is null!");
            }

            var acc = device.GetModule<MbientLab.MetaWear.Sensor.IAccelerometer>();
            // Start the acceleration data
            acc.Acceleration.Start();
            // Put accelerometer in active mode
            acc.Start();
        }

        public async virtual Task<IMetaWearBoard> ConnectToDevice(BluetoothLEDevice device, int retries = 1)
        {
            _metawearDevice = Application.GetMetaWearBoard(device);

            if (_metawearDevice == null)
            {
                throw new ArgumentNullException("The MetaWear device is null!");
            }

            // How long the API should wait (in milliseconds) before a required response is received
            _metawearDevice.TimeForResponse = 5000;

            int x = retries;

            do
            {
                try
                {
                    await _metawearDevice.InitializeAsync();
                    retries = -1;
                }
                catch (Exception e)
                {
                    retries--;
                }
            } while (retries > 0);

            if (retries == 0)
            {
                return null;
            }
            else
            {
                return _metawearDevice;
            }
        }

        private string ConvertToMAC(ulong value)
        {
            string hexString = value.ToString("X");
            // Pad the hex string with zeros on the left until 12 nibbles (6 bytes) are present
            hexString = hexString.PadLeft(12, '0');
            return hexString.Insert(2, ":").Insert(5, ":").Insert(8, ":").Insert(11, ":").Insert(14, ":");
        }
    }
}

Я запустил его, используя

Task.Run(async () => await Connect(MAC, 3));

1 Ответ

1 голос
/ 27 сентября 2019

Task.Run() упаковывает ваш код в Task.Задача выполняется, но вам нужно зафиксировать результат выполнения Задачи.Так что вам нужно сделать это:

var task = Task.Run(async () => await Connect(MAC, 3));

await task;

Но нет никакого смысла делать это.Если вы хотите дождаться асинхронной операции, просто сделайте это:

await Connect(Mac, 3)
...