Russian Qt Forum

Программирование => Общий => Тема начата: a1ien от Июня 21, 2012, 15:23



Название: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 21, 2012, 15:23
Использую QextSerialPort для работы с COM портом.
Есть клсс PortListener у него есть
такой слот
Код
C++ (Qt)
void PortListener::onReadyRead()
{
   emit DataRead(port->readAll());
}
Который связан таким образом с QextSerialPort.
Код
C++ (Qt)
connect(port/*QextSerialPort*/, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
Также генерирует сигнал DataRead собственно с данными полученными по COM порту.
На другом концу весит некий девайс с которым нужно общаться по определенному протоколу.

А теперь собственно вопрос.
Как лучше всего(и правильнее) реализовать взаимодействие с ним.

Щас у меня так сделано(скорее всего это очень криво)
Код
C++ (Qt)
 
void MainWindow::on_Sync_clicked()
{
   ui->Sync->setEnabled(false);
   PortSettings comPortSettings;
   comPortSettings.BaudRate=BAUD9600;
   comPortSettings.DataBits=DATA_8;
   comPortSettings.FlowControl=FLOW_OFF;
   comPortSettings.Parity=PAR_NONE;
   comPortSettings.StopBits=STOP_1;
   listener->open(ui->comPorts->currentText(),comPortSettings);
   listener->SendCommand(QByteArray(512,0x00));
 
}
void MainWindow::DataRead(const QByteArray& data) // слот которые соединен с сигналом DataRead у PortListener
{
 qDebug(data);
 QByteArray buf=data.toHex();
 switch(state)
   {
   case NOTSYNCKED:
     {
       if(buf.contains("0d0a3e")) {
           state=SYNCKED;
           listener->SendCommand(QByteArray::fromHex("4200c20100"));
           Sleep(300);
           listener->setBaudRate(BAUD115200);
           listener->SendCommand(QByteArray::fromHex("0d"));
 
         }
       break;
     }
   case SYNCKED:{
       if(buf.contains("0d0a3e")) {
           state=READY;
           SendBinary("fw.bin");
           Run();
         }
     }
 
   default:
     break;
   }
}
 

Что хотелось бы, чтобы была возможность и асинхронно работать и при этом оставить возможность синхронной работы.
например чтобы можно было сделать вот так(как еще один вариант)
Код
C++ (Qt)
void MainWindow::on_Sync_clicked()
{
   ui->Sync->setEnabled(false);
   PortSettings comPortSettings;
   comPortSettings.BaudRate=BAUD9600;
   comPortSettings.DataBits=DATA_8;
   comPortSettings.FlowControl=FLOW_OFF;
   comPortSettings.Parity=PAR_NONE;
   comPortSettings.StopBits=STOP_1;
   listener->open(ui->comPorts->currentText(),comPortSettings);
   listener->SendCommand(QByteArray(512,0x00));
QEventLoop eventLoop;
   connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit()));
   eventLoop.exec();
listener->SendCommand(QByteArray::fromHex("4200c20100"));
           Sleep(300);
           listener->setBaudRate(BAUD115200);
           listener->SendCommand(QByteArray::fromHex("0d"));
}


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 21, 2012, 15:31
Sleep в основном потоке детектед. Ну что сказать - учи потоки :D


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 21, 2012, 15:34
Да да Sleep, но тут эта функция выполняеться один раз.
Но собственно я по этом тоже справшивал как бы организовать синхронную работу)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: mutineer от Июня 21, 2012, 16:44
Да да Sleep, но тут эта функция выполняеться один раз.
Но собственно я по этом тоже справшивал как бы организовать синхронную работу)

Юзать отдельный поток для работы с портом


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 21, 2012, 17:45
Код
C++ (Qt)
Юзать отдельный поток для работы с портом
И чем это поможет? (я имею введу что мне это даст, я правда хочу понять)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: mutineer от Июня 21, 2012, 17:51
Код
C++ (Qt)
Юзать отдельный поток для работы с портом
И чем это поможет? (я имею введу что мне это даст, я правда хочу понять)

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


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 21, 2012, 17:52
Краткий ликбез. Ибо я ем кильку в томатном соусе и добр.

Поток - это там где исполняются твои команды.
У каждого приложения минимум 1 поток.
Именно 1 поток отрисовывает ГУИ(интерфейс).
Но если 1 будет рисовать, а второй работать с портом ПАРАЛЛЕЛЬНО, это же лучше 1? :)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 21, 2012, 17:59

Цитировать
Поток - это там где исполняются твои команды.
У каждого приложения минимум 1 поток.
Именно 1 поток отрисовывает ГУИ(интерфейс).
Но если 1 будет рисовать, а второй работать с портом ПАРАЛЛЕЛЬНО, это же лучше 1?
Да спасибо большое это все понятно. И я понимаю для чего это нужно вобще.
Но главный вопрос чем это поможет в решении задачи работать в некоторых моментах с портом синхронно а в остальных случаях асинхронно.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Igors от Июня 21, 2012, 18:17
Но если 1 будет рисовать, а второй работать с портом ПАРАЛЛЕЛЬНО, это же лучше 1? :)
А чем оно "лучше"? Только тем что "так часто делают"?  :)

Что хотелось бы, чтобы была возможность и асинхронно работать и при этом оставить возможность синхронной работы.
например чтобы можно было сделать вот так(как еще один вариант)
Так или иначе приходится ждать "ответа с той стороны" - наверное под синхронностью понимается "модальность" этого ожидания, типа дождались и потом продолжаем заниматься свои делом. Тогда можно действовать через QApplication::processEvents - и подобрать нужный флажок-параметр. А sleep конечно плохо


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 21, 2012, 18:49
Если много рисовать, или ждать. То 1 поток это плохо :D Это аксиома, подтверждения не требующая :D

Не спорю, в 1 поток создать работоспособную прекрасную программу возможно. Но позже вылезают обидные косячки :D


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Igors от Июня 21, 2012, 19:04
Если много рисовать, или ждать. То 1 поток это плохо :D Это аксиома, подтверждения не требующая :D
Один тут давеча тоже выдвигал аксиомы - у него подучились?  :)

Не спорю, в 1 поток создать работоспособную прекрасную программу возможно. Но позже вылезают обидные косячки :D
Насколько я понял, человек спрашивает не об этом. Лучше ли читать в др нитке - но то уже др вопрос. А спрашивалось как не отдавать управление, тут без разницы в какой нитке читатель, все равно придется крутить вторичный цикл


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 21, 2012, 19:30
Igors не забываем - каждый советует так, как сам бы поступил :D

Способов реализации - море. Я выбираю несколько потоков.

Что даст - возможность работать с портом "без оглядки" на отображение. Синхронность или асинхронность сам определишь :)

Что даст реализация без потоков на таймерах - хз. Даст реализацию работы с портом без потоков :D


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: kuzulis от Июня 21, 2012, 21:03
А никто еще не посоветовал использовать QtSerialPort (http://qt-project.org/wiki/QtSerialPort_Russian) вместо QextSerialPort, т.к. последний имеет очень кривую архитектуру. :)

И если будешь использовать QtSerialPort - то никакие потоки не нужны.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 21, 2012, 21:16
QtSerialPort вроде под Qt 5.0 пишется. И ещё в процессе разработки, не?

Я лично использую свою самописную библиотечку - ибо все имеющиеся для qt (типа Qext и прочая) жутко глючили и хреново передавали :D


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Kurles от Июня 21, 2012, 21:55
QtSerialPort вроде под Qt 5.0 пишется. И ещё в процессе разработки, не?
под 4.7.4 тоже робит ) И отлично так робит, зуб даю :)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: kuzulis от Июня 22, 2012, 10:02
Цитата: Bepec
QtSerialPort вроде под Qt 5.0 пишется. И ещё в процессе разработки, не?
А ты почитай по ссылке что я дал, и все узнаешь  :)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 22, 2012, 13:17
Сколько всего на отвечали))
1) Спасибо за ссылку на QtSerialPort посмотрю что да как.
2) По поводу Sleep это просто была временная заглушка.
3) Объясните пожалуйста как(и чем) помогли бы дополнительные потоки в работа частично синхронно, а частично асинхронно.
Грубо говоря мне вначале надо выполнить синхронно некоторую инициализацию на стороне девайся, а потом я бы хотел асинхронно кидать и ловить от него сообщения.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 22, 2012, 14:07
Порт работает асинхронно так то, но программно ты можешь что угодно написать. Флаги/стражи в вперёд.

Уже пояснял:

Код:
Поток - это там где исполняются твои команды.
У каждого приложения минимум 1 поток.
Именно 1 поток отрисовывает ГУИ(интерфейс).
Но если 1 будет рисовать, а второй работать с портом ПАРАЛЛЕЛЬНО, это же лучше 1?

Если это не понятно, то запусти Тотал коммандер. И попытайся скопировать какой-нить большой файл. И у тебя будет открыт второй поток, который отрисует окошечко для копирования, который ты можешь остановить/притормозить/перемещать, независимо от основного потока.



Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 22, 2012, 14:48
Да понимаю я что-такое поток.
Щас объясню что непонятно.

У нас есть функция записи в порт. У нас есть слот который вызваться когда нам приходят данные. Они работаю асинхронно, это понятно.
Дальше если мы будем ждать в on_Sync_clicked() когда нам придет что-то в порт, то понятно что мы этого некогда не дождемся, так-как у нас один поток.
Это все понятно.
Не доконца ясно почему нам помогает QEventLoop(точнее вот эта конструкция
Код
C++ (Qt)
QEventLoop eventLoop;
   connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit()));
   eventLoop.exec();
), eventLoop же не создает отдельного потока(почему он может получить сигнал onReadyRead())
Понял почему, он запускает цикл ожидания события.

Дальше из этого всего вытикает вопрос, как делать синхронно, Я так понимаю вы предлагате такую вещь,
Мы переносим класс PortListener в отдельный поток, в функции MainWindow::on_Sync_clicked()(в которой нам нужно поработать синхронно) мы расставляем например мютексы(тут опять вопрос, медь если мы там поставим мютекс то GUI поток зависнит, и как нам ждать результат )

Еще раз я понимаю что-такое потоки, но не понимаю как ОНИ НАМ ПОМОГУТ.
Можете описать что в каждом потоке вы предлагате мне сделать.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Igors от Июня 22, 2012, 15:15
Сколько всего на отвечали))
Ну так если не нравится - никто не мешает "проиктировать" самому  :)

У нас есть функция записи в порт. У нас есть слот который вызваться когда нам приходят данные. Они работаю асинхронно, это понятно.
Дальше если мы будем ждать в on_Sync_clicked() когда нам придет что-то в порт, то понятно что мы этого некогда не дождемся, так-как у нас один поток.
Очень даже дождемся если будем ждать примерно так
Код
C++ (Qt)
// какие-то действия, напр инициализация
connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit(), Qt::QueuedConnection));
...
while (true) {
QApplication::processEvents(..);
..
if (flagQuit) break;
}
// продолжаем делать что хотели
 
Сигнал с QueuedConnection - это event которое придет в свой eventLoop (в данном случае главной нитки) если мы скажем ему обрабатывать события (processEvents). Надо только в слоте quit его опознать, (напр взвести флажок) чтобы "вытикать" из цикла while  :)



Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 22, 2012, 15:48
Уважаемый a1ien. Вы знаете определение потока. Вы молодец :)

Но вы видимо слабо знаете сигнал-слотовую архитектуру и межпотоковое взаимодействие. Советую их вам подучить, а так же почитать Бланшета.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 22, 2012, 16:08
Bepec, вы типичный троль с вами общаться даже не хочеться.

Igors,
Цитировать
Цитировать
Сколько всего на отвечали))
Ну так если не нравится - никто не мешает "проиктировать" самому
Это наоборот было в позитивном ключе сказано, то есть я только рад что много ответов.
Спасибо большое вам а ваши ответы они дают направление куда стоит копать.
Код
C++ (Qt)
// какие-то действия, напр инициализация
connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit(), Qt::QueuedConnection));
...
while (true) {
QApplication::processEvents(..);
..
if (flagQuit) break;
}
// продолжаем делать что хотели
Я так понимаю что это почти тоже самое, что и мой код с
Код
C++ (Qt)
QEventLoop eventLoop;
   connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit()));
   eventLoop.exec();
Просто другая реализация, а нету более красивого примера с идеологической точки зрения?)


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Igors от Июня 22, 2012, 16:29
Я так понимаю что это почти тоже самое, что и мой код с
Код
C++ (Qt)
QEventLoop eventLoop;
   connect( listener->port,SIGNAL(onReadyRead()),&eventLoop, SLOT(quit()));
   eventLoop.exec();
Просто другая реализация, а нету более красивого примера с идеологической точки зрения?)
С идеологической все это "вторичный цикл событий", который широко используется, и это нормальная практика. Однако запускать свой локальный eventLoop обычно невыгодно, т.к. UI остается замороженным, приходится прилагать усилия чтобы прервать операцию и.т.п. Практичнее создать локальный объект, у него слот, он и получит сигнал в текущем eventLoop.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: a1ien от Июня 22, 2012, 16:36
Спасибо большое. Вопрос можно считать закрытым.


Название: Re: Как бы лучше спроиктировать такую архитектуру.
Отправлено: Bepec от Июня 22, 2012, 16:38
И тут троллем обзывают :D

Видимо что-то с кармой, или с желанием спрашивающих узнать ответ на свой вопрос :)