Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Вопрос по многопоточке


Автор: ДобренькийПапаша 17.5.2011, 19:42
Код

static void Main(string[] args)
        {
            CardDispenser dispenser = new CardDispenser("COM4", 9600, Parity.None, 8, StopBits.One);
            
            dispenser.Send(dispenser.Command["DC"]);
            
            Thread.Sleep(5000); //Без этой строки следующий посыл команды выполняется раньше времени

            dispenser.Send(dispenser.Command["CP"]);

            dispenser.Close();
            Console.ReadLine();
        }       


Код

//в функции Send посыл данных на com-порт
this.Write(batch.BatchByteSequence.ToArray(), 0, batch.BatchByteSequence.Count);


Код

private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            string response = this.ReadExisting();
            byte[] byteResponse = Encoding.GetBytes(response);
            int answerCode = byteResponse[0];
            if (answerCode == 6)
            {
                Send(Command["ENQ"]);
            }
        }


Нужно, чтобы Handler отработал и вообще всё сначала отработало, а только потом выполнялась следующая команда. Sleep() вызывать не дело. А с многопоточкой я почти не работал. Как лучше здесь поступить?

Автор: -Mikle- 17.5.2011, 22:02
Вот блокирующий (синхронный) вариант:

Код

........................
AutoResetEvent waitHandle = new AutoResetEvent(false);

bool Send(........, int timeout)
{
  ...........
  return waitHandle.Wait(timeout);
}

void DataReceivedHandler(..........)
{
   .............
   waitHandle.Set();
}


Это не многопоточный и самый самый простой вариант. Send можно вызывать только из одного одновременно.
Подходит?

Добавлено через 3 минуты и 40 секунд
Можно еще делать очередь и обрабатывать очередь по завершению предыдущей команды.

Автор: ДобренькийПапаша 18.5.2011, 20:15
Я переформулирую проблему топика. Код я неправильный привёл. Проблема такая:

Метод Send отправляет на порт пакет данных (команду) и возвращает ответ (тоже пакет данных - класс Batch). DataReceived-событие возбуждается системой, когда ей в голову придёт (пока там команда дойдёт до порта и устройство начнёт отвечать). Ожидание ответа (срабатывание события) сейчас мной сделано через цикл while как видно в методе ReceiveResponseBatch(). Вообще говоря, это работает. Но как-то это извращённо и некрасиво. Как можно сделать красиво?
Код

private bool IsAnswerReceived=false;

        //Получение данных       
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            IsAnswerReceived = true;
        }

        //Отправление данных
        public override Batch Send(CommandAttributes attributes)
        {
            Batch batch = new Batch(attributes.CommandName);
            SendBatch(batch);

            return ReceiveResponseBatch();
        }

        //Получение данных
        private Batch ReceiveResponseBatch()
        {
            int waitingIntervals = 0;
            while(!IsAnswerReceived)
            {
                waitingIntervals++;
                if (waitingIntervals > 50) break;
                Thread.Sleep(200);
            }

            if (IsAnswerReceived)
            {
                string response = this.ReadExisting();
                byte[] byteResponse = Encoding.GetBytes(response);
                
                IsAnswerReceived = false;

                return new Batch(byteResponse);
            }            
            return null;
        }


А как очередь организовать? Что ты здесь имел ввиду конкретно?

Автор: neic 19.5.2011, 00:55
Может стоит использовать Semaphore? и очередь автоматически формируется и управлять легче всем эти делом будет.

Автор: -Mikle- 19.5.2011, 07:45
Я приводил код выше. Если смотреть по аналогии с вашим, то waitHandle - это как бы флаг IsAnswerReceived.
То есть:
Код

        private AutoResetEvent waitHandle = new AutoResetEvent(false);

        //Получение данных       
        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            waitHandle.Set();
        }

        //Отправление данных
        public override Batch Send(CommandAttributes attributes, int timeout = 10000)
        {
            Batch batch = new Batch(attributes.CommandName);
            SendBatch(batch);
            return (waitHandle.Wait(timeout)) ? ReceiveResponseBatch() : null;
        }

        //Получение данных
        private Batch ReceiveResponseBatch()
        {
            string response = this.ReadExisting();
            byte[] byteResponse = Encoding.GetBytes(response);
            return new Batch(byteResponse);
        }


Посмотри еще на Semaphore, как посоветовал neic, его тоже можно прикрутить тут.

А про очередь, я имел ввиду асинхронный вариант. То есть метод Send ничего не возвращает, обработанные ответы передаются событием или делегатом. То есть по обычному асинхронному шаблону. Пример писать щас не хочу, потому что не знаю нужен ли тебе он.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)