@Ramirag
Я человек.

Как реализовать выполнение очереди комманд в дочернем потоке?

У меня есть COM порт по которому я шлю наборы команд устройству. Разработчики устройства не реализовали никакой очереди принятых команд, потому если послать сразу две команды, устройство виснет. Потому мне надо ставить небольшую задержку между отправкой команд. Хотелось бы реализовать это все прозрачно, что бы не думать об этом баге на протяжении всего проекта.
Как я себе это представляю. У меня есть очередь команд на отправку, которую можно пополнять. И мне надо что бы эти команды отправлялись адресату последовательно в дочернем потоке.
Я написал нечто такое:
private void AddCommand(Byte[] command)
        {
            _commandQueue.Enqueue(command);
            if (_commandTask.IsCompleted)
                _commandTask.Start();
        }
        private void SendCommand()
        {
            Byte[] sendBytes;
            while (!_commandQueue.IsEmpty)
            {
                if (_commandQueue.TryDequeue(out sendBytes))
                {
                    _port.Write(sendBytes, 0, sendBytes.Length);
                    Thread.Sleep(100);
                }
            }
        }

Но этот код подвержен багу. Я добавил команду в список. Поток еще работает, потому создание потока пропускается. Но поток для отправки уже вышел из цикла и следовательно ничего не отправит. Ну и у меня нет потока для отправки и в очереди есть команда. Как мне быть?
Была идея использовать обычный поток, который засыпает на некоторое время, если нет команд в очереди. А добавляющий метод будит его Interrupt'ом. Тут выходит, у меня один поток постоянно висит, что мне не нравится. Да и я при ситуации описанной выше команда будет отправлена, но с задержкой равной времени сна.
  • Вопрос задан
  • 3088 просмотров
Решения вопроса 2
@mayorovp
Используйте ConcurrentQueue, обернутый в BlockingCollection, для передачи сообщений между потоками. Тот поток, который читает команды из очереди, может вообще висеть все время - пока он один и он спит, это вообще не проблема.
Ответ написан
Mrrl
@Mrrl
Заводчик кардиганов
В цикле в условие while (!_commandQueue.IsEmpty) добавить проверку какого-нибудь внешнего флага, который установить в false, когда источник команд примет решение, что делать больше ничего не надо: while(fgoing || !_commandQueue.IsEmpty).
По хорошему, надо бы при пустой очереди ждать не секунду, а какого-нибудь события, которое возникнет, когда добавится новая команда. Иначе команду, которая пришла через 1.2 секунды после первой, он отправит только через две секунды.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@Oxoron
Шарпер
Используйте mutex, locker, или любой другой механизм блокировки (в обоих методах).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы