0

В ViewModel имеется команда, которая запускает загрузку данных с порта и расшифровку их:

void ReadData_Execute(object parameter)
    {            
        ReadingData.StartLoadData();
        DecodData.StartDecod();
    }

Вот код StartLoad :

public static void StartLoadData()
    {
        if (ThreadLoad != null)
            ThreadLoad = null;
        StatusThread = true;
        ThreadLoad.Start();
    }

Свойство ThreadLoad :

private static Thread ThreadLoad
    {
        get
        {
            if (_threadLoad == null)
                _threadLoad = new Thread(LoadData);
            return _threadLoad;
        }
        set { _threadLoad = value; }
    }

Вот метод LoadData, который вызывается в этом потоке:

private static void LoadData()
    {            
        while (StatusThread)
        {
            WriteData.WritingData.WriteCommand();
            byte[] command = CreatePackage(InitNumber);
            byte[] data = CPort.ReadData(command);
            //добавить проверку контрольной суммы.
            ByteInformation.AddByte(data, InitNumber);
            InitNumber += 25;
        }
    }

Вопрос: как перехватывать исключения, которые возникают в методе LoadData? В основном ошибки должны возникать с портом, но обычными try/catch не удается отловить исключения из другого потока...

2 Answers2

2

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

Если вы перейдёте на Task и async/await, то там, да, исключения доставляются тем, кто получает результат Task'а.


Вы используете переменные (например, StatusThread) из нескольких потоков без синхронизации. Это неверно, так делать нельзя.

VladD
  • 206,799
  • Vlad: много ли времени займет переход на Task, если о них только читал, но нет опыта? Как тогда остановить поток из GUI? – UporotayaPanda Jan 04 '18 at 13:27
  • @UporotayaPanda: У меня прошло быстро, но я не знаю, насколько ваш код завязан на потоки. В любом случае, async/await — это самая крутая фича C#, и пользоваться C# без async/await — всё равно что купить спортивный автомобиль, и ездить только по городу со скоростью 50 км/ч. – VladD Jan 04 '18 at 13:30
  • у меня один поток читает по кругу данные из системы через порт и пишет их в массив. Второй по кругу эти данные расшифровывает в "человеческий" вид. По предыдущему комментарию я уже понял, что делить один массив между двумя потоками это плохо. – UporotayaPanda Jan 04 '18 at 13:33
  • @UporotayaPanda: Вот пара примеров: https://ru.stackoverflow.com/q/760720/10105, https://ru.stackoverflow.com/q/597228/10105 – VladD Jan 04 '18 at 13:40
  • async/await интересная вещь, изучу ее на досуге. – UporotayaPanda Jan 04 '18 at 14:38
  • Но проект написан на .Net 4.0. Как я понял из описания на msdn, все описанное появилось только в 4.5 – UporotayaPanda Jan 04 '18 at 14:41
  • @UporotayaPanda: Ага, так и есть. Но мне кажется, имеет смысл перейти на более новую версию фреймворка, а то уже C# 7.3 на дворе, а вы всё на C# 4. – VladD Jan 04 '18 at 15:14
0

Можно пробовать отлавливать ошибки в дочернем процессе, но вместо того, чтобы их обрабатывать, запихивать в глобальную переменную и прерывать процесс, а в главном процессе уже проводить обработку.

  • Привидите пртмер кода. – 0xdb Jan 04 '18 at 14:06
  • @0xdb, исключение - класс. Любой класс можно запихнуть в переменную. Я в java не мастер, пример дать не могу, но нужно всего - лишь поставить try - catch в LoadData, сохранять ошибку в глобальную переменную (назову её fatal), а потом, когда параллельная работа закончится, делать проверку, что fatal != null. Если fatal != null, то производить обработку ошибки, указанной в fatal. Если fatal == null, то ошибки нет. – user263096 Jan 04 '18 at 14:18
  • @user263096: Глобальные переменные — не лучшая практика. Что если у вас два потока через некоторый промежуток времени выбросят исключение, что делать в этом случае? – VladD Jan 04 '18 at 15:16
  • @VladD, создать две глобальные переменные. – user263096 Jan 04 '18 at 15:19
  • @VladD, или использовать список (List), в который кидать ошибки. – user263096 Jan 04 '18 at 15:19
  • А если количество потоков неизвестно на этапе компиляции, наши действия? – VladD Jan 04 '18 at 15:19
  • Если список, то как мы узнаем, в каком из потоков произошла ошибка? – VladD Jan 04 '18 at 15:20
  • @VladD, можно сделать список, состоящий из структур. А структура может состоять из ID потока и самой ошибки. – user263096 Jan 04 '18 at 15:20
  • @VladD, ещё проблемы видите? Критика всегда полезна. – user263096 Jan 04 '18 at 15:25
  • Окей,а если в одном потоке произошло несколько исключений? Как отличить, какое из заданий завершилось с ошибкой? – VladD Jan 04 '18 at 15:27
  • Для сравнения, смотрите, как просто доставить исключение из другого потока при помощи async/await: https://ideone.com/5Wnppr – VladD Jan 04 '18 at 15:29
  • @VladD, теоретически, выполняемое задание тоже можно занести в структуру, но тогда она и вправду становится слишком большой. Пожалуй да, Вы правы, async/await лучше. – user263096 Jan 04 '18 at 15:32
  • @user263096: В принципе, можно каждому заданию дать по id, и держать исключение и id задания. Но вот что мне не очень нравится, это глобальная общедоступная переменная. Это сразу приглашение к ошибкам. Плюс, раз эта переменная разделяется между потоками, то нужна синхронизация, что тоже не так уж хорошо (т. к. надо не напутать с ней). – VladD Jan 04 '18 at 15:35