Возможно ли исключение быть перехваченным асинхронно, не ожидая задачи? - PullRequest
0 голосов
/ 17 октября 2018

У меня есть класс CAN-устройств низкого уровня, для которого я хотел бы создать событие onMessageReceive.У меня есть несколько классов устройств высокого уровня, которые могут использовать экземпляр этого класса CAN.Я хотел бы присоединить анализатор сообщений класса устройств высокого уровня к событию onMessageReceive устройства CAN низкого уровня.Таким образом, когда низкоуровневый класс принимает пакет, он анализируется в высокоуровневом классе с помощью задачи низкоуровневого считывателя.Вставить в код это будет выглядеть следующим образом:

void Main()
    {
        try
        {
            using (HighLevelDevice highLevelDevice = new HighLevelDevice())
            {
                while (true)
                {
                    // Use the properties/fields in highLevelDevice to make testing decisions.
                }
            }
        }
        catch (Exception)
        {
            // If the low level CAN reader task encounters an error I would like for it to asynchronously propogate up to here.
            throw;
        }
    }


    public class HighLevelDevice
    {
        private LowLevelCan lowLevelCanInstance;

        public HighLevelDevice()
        {
            lowLevelCanInstance = new LowLevelCan(this.ProcessPacket);
        }

        private void ProcessPacket(Packet packet)
        {
            // Convert packet contents into high level device properties/fields.
        }
    }

    public class LowLevelCan
    {
        private delegate void ProcessPacketDelegate(Packet packet);

        private ProcessPacketDelegate processPacket;

        private Task readerTask;

        public LowLevelCan(Action<Packet> processPacketFunction)
        {
            processPacket = new ProcessPacketDelegate(processPacketFunction);
            readerTask = Task.Run(() => readerMethod());
        }

        private async Task readerMethod()
        {
            while(notCancelled) // This would be a cancellation token, but I left that out for simplicity.
            {
                processPacket(await Task.Run(() => getNextPacket()));
            }
        }

        private Packet getNextPacket()
        {
            // Wait for next packet and then return it.
            return new Packet();
        }
    }

    public class Packet
    {
        // Data packet fields would go here.
    }

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

Эта реализация убьет читателя, но поток highLevelDevice продолжает игнорироваться.Это было бы хорошо, если бы я сохранил ошибку и периодически проверял состояние в главном потоке.Я просто хотел бы найти решение, которое позволит избежать этого, если это возможно.

Я пробовал различные варианты сообщений об ошибках и отчетов о ходе работы, созданных в потоке, в котором завершается highLevelDevice.Они не работают должным образом / или я не понимаю, что они делают правильно.

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Ваш заглавный вопрос применяется, когда вы хотите запустить метод асинхронно и позднее синхронизироваться с ним, чтобы получить результат.Однако основная часть вашего вопроса - это действительно одновременный доступ к общему состоянию (высокоуровневое устройство). Состояние читается из вашего потока Main, но записывается в фоновом потоке вашим устройством низкого уровня.

Решение заключается в создании свойства Error в устройстве высокого уровня, которое можно использовать для координации обработки ошибок в двух потоках:

  • перехватывать любые исключения, выдаваемыеваше низкоуровневое устройство и распространите их на высокоуровневое устройство (см. ниже), которое будет хранить ошибку в свойстве Error.
  • инкапсулирует все чтения устройства HL в свойствах, чтобы при чтении вы могли проверить Error.Если произошла ошибка, сгенерируйте исключение с деталями (которые будут перехвачены и обработаны в Main.)

Чистый эффект состоит в том, что исключения из устройства низкого уровня были распространены наMain.

В качестве примечания, ваш вопрос подразумевает асинхронный шаблон на основе задач, но ваше низкоуровневое устройство фактически написано на основе событий.См. Шаблоны асинхронного программирования .

Каждый шаблон имеет свой особый метод для распространения ошибок:

Ваш Task.Run действительно только дает эффект низкоуровневой петле устройства в другом потоке к Main Вы не можете ждать readerTask, потому что он представляет обработкуцикл в целом, а не отдельный пакет обновления.Вместо этого отдельные обновления пакетов уведомляются через события.

Подводя итог, можно сказать, что когда низкоуровневое устройство ловит исключение, оно должно инициировать событие и передавать подробности исключения в аргументах события события.Устройство высокого уровня получит событие и сохранит данные в свойстве Error.Все это происходит в вашей фоновой ветке.В главном потоке, когда обнаружена ошибка во время чтения свойства на устройстве высокого уровня, получатель должен выдать исключение с деталями Error, которые должны быть обработаны в Main.

0 голосов
/ 17 октября 2018

Нет.Я проверил это, и вам нужно дождаться завершения задачи, чтобы вызвать исключение.Либо дождитесь выполнения Задачи, либо используйте Task.Wait (), чтобы дождаться ее завершения.

Я пытался использовать этот код, но он не уловил исключение.

        try
        {
            var task = Task.Run(() => WaitASecond());

            task.ContinueWith(failedTask => throw failedTask.Exception, TaskContinuationOptions.OnlyOnFaulted);
        }
        catch (Exception ex)
        {
            throw;
        }

Когда ядобавлено task.Wait() в var task = Task.Run(() => WaitASecond());, оно перехватило статистическое исключение и выдало его.

Вам нужно будет дождаться завершения всех ваших задач, чтобы перехватить исключение и вызвать его в Main ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...