Подтвердить что ты не робот

Правильно?

Я инженер-программист, обладающий довольно большим опытом работы в C и встроенных технологиях. В настоящее время я занят написанием некоторых приложений на С# (.NET), которые используют оборудование для сбора данных. Теперь следующее, для меня, вопрос:

Например: у меня есть машина, у которой есть конечный выключатель для определения конечного положения оси. Теперь я использую модуль сбора данных USB для чтения данных. В настоящее время я использую Thread для непрерывного чтения статуса порта.

На этом устройстве нет функций прерывания.

Мой вопрос: Правильно ли это? Должен ли я использовать таймеры, потоки или задачи? Я знаю, что опрос - это то, что большинство из вас, парни, "ненавидят", но любое предложение приветствуется!

4b9b3361

Ответ 1

IMO сильно зависит от вашей конкретной среды, но сначала: в большинстве случаев больше не следует использовать Threads. Tasks - это более удобное и более эффективное решение для этого.

Вернуться к вашему вопросу:

  • Низкий интервал опроса: таймер и опрос в событии Tick
  • Medium: Task и используя await Task.Delay(delay)
  • Высокий: Task и используя Thread.Sleep(delay)

Почему "низкое решение": таймер прост в обращении и останавливается. Не нужно беспокоиться о потоках/задачах, выполняющихся в фоновом режиме, но обработка происходит в основном потоке.

Почему "среднее решение": await Task.Delay(delay) не блокирует поток потока пула, но из-за переключения контекста минимальная задержка составляет ~ 15 мс.

"Высокое решение" можно использовать при задержке 1 мс - мы на самом деле делаем это здесь, чтобы опросить наше измерительное устройство USB.

Это может быть реализовано следующим образом:

int delay = 1;
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var listener = Task.Factory.StartNew(() =>
    {
        while(true)
        {
            //poll HW
            Thread.Sleep(delay);
            if(token.IsCancellationRequested)
                break;
        }

        //cleanup
    }, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

В большинстве случаев вы можете просто использовать Task.Run(() => DoWork(), token), но нет перегрузки для предоставления опции TaskCreationOptions.LongRunning, которая сообщает планировщику задач не использовать поток потоков нитей.
Но, как вы видите, Tasks легче обрабатывать (и await может, но здесь не применяется). Особенно "остановка" просто вызывает cancellationTokenSource.Cancel() в этой реализации из любого места в коде.

Вы даже можете поделиться этим токеном в нескольких действиях и немедленно остановить их. Также еще не начатые задачи даже не запускаются, когда токен отменен.

Вы также можете приложить другое действие к задаче для запуска после одной задачи:

listener.ContinueWith(t => ShutDown(t));

Затем выполняется после завершения прослушивателя, и вы можете выполнить очистку (t.Exception содержит исключение действия задачи, если оно не было выполнено успешно).

Ответ 2

Невозможно избежать опроса IMO.

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