Russian Qt Forum
Ноябрь 24, 2024, 08:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 ... 58 59 [60] 61 62 ... 88   Вниз
  Печать  
Автор Тема: Создаю библиотеку для работы с последовательными портами. [УШЕЛ ИЗ ПРОЕКТА].  (Прочитано 786163 раз)
b-s-a
Гость
« Ответ #885 : Март 22, 2012, 14:25 »

Честно говоря, не настораживает. Функция редко используемая (т.е. не ежесекундно). Ну а тот, кто использует часто - ССЗБ.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #886 : Март 22, 2012, 16:27 »

OK, сделаю Улыбающийся

Следующая задача:

я озадачился производительностью операций I/O и положение удручающее (по крайней мере в Windows).

Под виндой планирую перейти на полностью асинхронные операции, используя приватный класс из
Цитировать
src\corelib\io\qwinoverlappedionotifier_p.h
и процесс чтения выполнить аналогично реализации в
Цитировать
src\corelib\io\qwindowspipereader_p.h

Модификации подвергнутся нативные методы Engine::read/write, т.е.

Цитировать
вместо read() будут два метода startAsyncRead() и completeAsyncRead()
вместо write() будут два метода startAsyncWrite() и completeAsyncWrite()

в принципе, для операции write достаточно только startAsyncWrite().

т.е. цепочка при чтении предполагается примерно такая:

при евенте об приходе данных в UART:
WinSerialPortEngine::event() -> SerialPortPrivate::canReadNotification(true) ->WinSerialPortEngine::startAsyncRead(*data, len)

при уведомлении об завершении I/O
void WinSerialPortEngine::notify(int bytesTransferred, int error) -> SerialPortPrivate::canReadNotification(false) -> WinSerialPortEngine::completeAsyncRead()


serialportengine_win.cpp
Код
C++ (Qt)
bool WinSerialPortEngine::event(QEvent *e)
{
   bool ret = false;
   if (e->type() == QEvent::WinEventAct) {
...
...
       if (EV_RXCHAR & m_currentMask & m_desiredMask) {
           dptr->canReadNotification(true);
           ret = true;
       }
...
...
...
}
 
// слот, срабатывающий по завершению асинхронной I/O операции
void WinSerialPortEngine::notify(int bytesTransferred, int error)
{
   if (error)
       return;
...
   m_bytesTransferred = bytesTransferred;
...
   dptr->canReadNotification(false); // false - флаг того что данные прочитаны, необходимо завершить операцию
...
}
 
bool WinSerialPortEngine::startAsyncRead(*data, len)
{
   // тут данные будут считываться в область памяти по указателю data
   ::ReadFile(...)
   // но реальное кол-во прочитанных байт мы из ReadFile не получим,
   // т.к. это кол-во мы узнаем позднее после завершение Overlapped операции
   // поэтому сейчай возвратим или true или false
}
 
qint64 WinSerialPortEngine::completeAsyncRead()
{
   // тут возвращаем реальное кол-во прочитанных байт
   return m_bytesTransferred;
}
 
 
 

serialport.cpp
Код
C++ (Qt)
bool SerialPortPrivate::canReadNotification(bool starting)
{
   if (starting) { // Если старт аси
       // Разного рода проверки, отключение на время нотификации для чтения и т.п.
       ...
       // Выделение дополнительного размера для кольцевого буфера и
       // получение указателя на кусок *data в который можно записать len байт
       ...
 
       // старт асинхронной операции чтения
       engine->startAsyncRead(*data, len);
 
       readSequenceStarted = true;
       return true;
   }
 
   // Это место означает, что необходимо завершить операчию чтения
 
   // Разного рода проверки и т.п.
   ...
 
   //получаем реальное кол-во прочитанных байт
 
   bytesRead = engine->completeAsyncRead();
 
  // урезаем кольцевой буфер до реального значения,
  // т.к. прочитать могли меньше чем запросили в len
 
  // послать readyRead() и т.п.
}
 

как то так примерно это должно выглядеть.

Теперь вопрос к тебе, b-s-a:

можно ли что-то аналогичное провернуть и для *nix?

там же вроде тоже есть функции асинхронного I/O типа async_read/write!

---

UPD: Что думают по этому поводу другие участники? Может есть другие предложения?
« Последнее редактирование: Март 22, 2012, 16:56 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
QuAzI
Гость
« Ответ #887 : Март 22, 2012, 17:40 »

А как-то сделать и синхронный режим и не синхронный не получится? Т.е. два варианта. У меня например есть железки, ака фискальные регистраторы (на базе специфического трёхпозиционного принтера Epson TM-U950), так они очень нервные в этом плане. Часто отказываются даже с платами расширения COM-портов работать (есть таких в хозяйстве, в основном от VSCom) или на некоторых отдельных материнках. Хотя возможно там ещё и приколы с теперяшними драйверами (своя прослойка между ФР и рабочим софтом). Писали их пьяные студенты-растаманы в прошлом веке на заборе.
« Последнее редактирование: Март 22, 2012, 17:44 от QuAzI » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #888 : Март 22, 2012, 18:01 »

Цитировать
А как-то сделать и синхронный режим и не синхронный не получится?
Неа, только асинхронный.

Цитировать
У меня например есть железки, ака фискальные регистраторы...
А причем тут принтеры? Поподробнее, в чем заключается нервность?
Записан

ArchLinux x86_64 / Win10 64 bit
QuAzI
Гость
« Ответ #889 : Март 22, 2012, 18:08 »

Это трёхпозиционные принтеры совмещённые с фискальной памятью - грубо говоря кассовые аппараты. Интерфейс подключения к ПК - RS232 (тобишь COM-порт). Нервность заключается в частом отказе ФР работать без видимых причин на некоторых конфигурациях железа, хотя переткнёшь на "встроенный" порт или на другую материнку - всё начинает работать как часы. Хотя на том же "проблемном" железе всяческие модемы, дата-кабели, считыватели пластиковых карточек работают так же без проблем. Т.е. вопрос где-то то ли в таймингах, то ли ещё в какой-то мелкой не стыковке. Железки не дешёвые и всё это тянется через налоговую и кучу другой бюрократии, заменить их грубо говоря не на что.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #890 : Март 22, 2012, 18:15 »

Ну, значит, принтеры в пролете, если такие жесткие требования к таймингам. Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #891 : Март 23, 2012, 11:12 »

Цитировать
Теперь вопрос к тебе, b-s-a:

можно ли что-то аналогичное провернуть и для *nix?

там же вроде тоже есть функции асинхронного I/O типа async_read/write!
Полностью асинхронного я ничего не припомню. Обычно, делается это через select. Т.е. select выходит в тот момент, когда данные приходят (ну или что-то случается). Но это должно быть исключительно в отдельном потоке, так как select работает синхронно. Зато он принимает множество дескрипторов, поэтому в программе может быть всего один поток с select. Можешь это использовать через QSocketNotifier и QEventDispatcherUNIX.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #892 : Март 23, 2012, 11:16 »

А как-же функции типа aio_read/aio_write ?
Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #893 : Март 23, 2012, 15:45 »

спасибо. не знал о них.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #894 : Март 23, 2012, 16:51 »

Цитировать
Цитата
спасибо. не знал о них.

Да пожалуйста. Улыбающийся

Поможешь с ними разобраться?

Я в принципе не очень понимаю как их можно прикрутить в плане нотификации...
Там вроде все заточено под Unix сигналы и каллбеки.

т.е. как я понимаю, можно или поветить каллбек, который вызовется по окончании I/O,
или каким-то образом отловить Unix сигнал, который излучится.

Весь вопрос - что предпочесть?
Можно ли отловить Unix сигнал через QSocketNotifier и т.п.?
Или тупо каллбек повесить?

В общем, есть вопрос к размышлению Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
apple_rtk
Гость
« Ответ #895 : Март 24, 2012, 16:52 »

Цитировать
Давно уже переписал свое приложение на WinAPI и забыл про эту проблему. Вчера коллеги бились о стену со своим приложением. Иногда обмен сбивается. Они в две головы решали эту проблему, багу в коде искали. Сегодня к обеду проблему решили )). Я поинтересовался - где была ошибка..... А они просто поменяли преобразователь. Ну я не удивился, когда выяснил чем они пользуются для связи с компортом - старая знакомая библиотека для компорта под Qt.  Смеющийся
Причем я грешил на Prolific, но они поставили другой преобразователь, тоже на Prolific-е и всё работает. А глючило и у меня и у них на преобразователе TU-S9. Может преобразователь кривой..... однако с GSM-модемом (Novacom) я такой-же глюк наблюдал, а с этим "глючным" TU-S9 на WinAPI всё работает как часы, без сбоев.

ps давно не слежу за развитием этой библиотеки, т.к. не использую, но может уже эту багу всё таки обнаружил автор и пофиксил.

Аналогичный случай: http://kernel.pro/articles/progs/prolific_qserialdevice/
Записан
b-s-a
Гость
« Ответ #896 : Март 25, 2012, 17:17 »

Я в принципе не очень понимаю как их можно прикрутить в плане нотификации...
Там вроде все заточено под Unix сигналы и каллбеки.
Я тоже не понимаю. Я даже не понимаю зачем это вообще нужно. Нотификация - это одно (делается на селекте), а вот асинхронное чтение/запись это совершенно другое. И я не уверен, что это реально кому-нибудь нужно. Если у него возникнет такая проблема, то он всегда может в отдельном потоке работать с портом.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #897 : Март 25, 2012, 17:49 »

Цитировать
Я тоже не понимаю. Я даже не понимаю зачем это вообще нужно.

Чтобы GUI не фризился в главном потоке.

Цитировать
Если у него возникнет такая проблема, то он всегда может в отдельном потоке работать с портом.
Это уже отговорки.  Улыбающийся

Цитировать
И я не уверен, что это реально кому-нибудь нужно.
Это позволит решить проблему подтормаживания евент лупа и сделать полностью асинхронную работу с I/O.

Вот из-за того, что в Qt все сделано на селектах и "синхронном" I/O (в частности, сокеты) - никто не использует
Qt в ответственных приложениях.

Непонятно зачем вообще в таком случае они сделали модули network (и вообще, подсистему I/O), если она кривая.

Когда-то на гиториусе видел от одного человека патч для Qt5, который позволял ускорить евент диспетчер,
используя вместо кросплатформенного POSIX select-а и т.п. - конкретные отдельные реализации данной сущности (epoll и т.п.) под каждую ОС.

Не знаю, почему патч  так и не влили в Qt (если не ошибаюсь)
« Последнее редактирование: Март 25, 2012, 17:55 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
b-s-a
Гость
« Ответ #898 : Март 25, 2012, 23:41 »

Чтобы GUI не фризился в главном потоке.
Интересно, что ты делаешь такое с портом, что GUI "фризится"? У меня все пашет, причем из-за гуя иногда слетает синхронизация.

Это позволит решить проблему подтормаживания евент лупа и сделать полностью асинхронную работу с I/O.

Вот из-за того, что в Qt все сделано на селектах и "синхронном" I/O (в частности, сокеты) - никто не использует
Qt в ответственных приложениях.
Потому что в ответственных приложения часто и гуя нет. Сидит себе демон/сервис и тихонечко работает. А завязываться на Qt, это повышать сложность приложения. А чем оно сложнее, тем больше ошибок. Ну и унификация дает о себе знать.

Непонятно зачем вообще в таком случае они сделали модули network (и вообще, подсистему I/O), если она кривая.
Потому что в бизнес-приложениях (для которых Qt в первую очередь и создан) эти компоненты нужны и там нет сильной нагрузки.

Когда-то на гиториусе видел от одного человека патч для Qt5, который позволял ускорить евент диспетчер,
используя вместо кросплатформенного POSIX select-а и т.п. - конкретные отдельные реализации данной сущности (epoll и т.п.) под каждую ОС.

Не знаю, почему патч  так и не влили в Qt (если не ошибаюсь)
Возможно, из-за сложностей с поддержкой. Лично меня все устраивает, кроме проблем с таймером в Windows - невозможно сделать ожидание на время меньшее, чем 18 мс. Приходится использовать PerfomanceCounters и циклы ожидания.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #899 : Март 26, 2012, 10:07 »

Цитировать
Интересно, что ты делаешь такое с портом, что GUI "фризится"? У меня все пашет, причем из-за гуя иногда слетает синхронизация.
Суть в том, что в винде при использовании overlapped операций приходится дожидаться их завершения, чтобы узнать сколько реально байт передалось/принялось

Например код при записи в порт:

Код
C++ (Qt)
qint64 WinSerialPortEngine::write(const char *data, qint64 len)
{
...
   DWORD writeBytes = 0;
   bool sucessResult = false;
 
   if (::WriteFile(m_descriptor, data, len, &writeBytes, &m_ovWrite))
       sucessResult = true;
   else {
       if (::GetLastError() == ERROR_IO_PENDING) {
           if (::GetOverlappedResult(m_descriptor, &m_ovWrite, &writeBytes, true))
               sucessResult = true;
       }
   }
...
...
   return quint64(writeBytes);
}
 

Вызывает тормоза на GetOverlappedResult() и тем они сильнее,
чем больший поток байт len мы передаем (проверено экспериментально).

Положительный момент этого метода в том, что после этого мы можем получить
реальное кол-во отправленых байт writeBytes.

В принципе, для операции записи я могу победить это - не дожидаясь
пока все байты отправятся и пока я получу writeBytes, т.е.
могу тупо сразу возвращать не writeBytes, а len.

Т.е. метод WinSerialPortEngine::write возвратит сразу такое кол-во
байт, которое было в него задано, т.е. "фейк" Улыбающийся

В принципе, я щитаю, что это выход для метода write.

Теперь рассмотрим метод read(), в котором используется таже
конструкция:

Код
C++ (Qt)
qint64 WinSerialPortEngine::read(char *data, qint64 len)
{
...
   DWORD readBytes = 0;
   bool sucessResult = false;
 
   if (::ReadFile(m_descriptor, data, len, &readBytes, &m_ovRead))
       sucessResult = true;
   else {
       if (::GetLastError() == ERROR_IO_PENDING) {
           if (::GetOverlappedResult(m_descriptor, &m_ovRead, &readBytes, true))
               sucessResult = true;
       }
   }
...
   return qint64(readBytes);
}
 

Но тут надо уточнить, что читаем мы данные, которые уже доступны для чтения в UART-е,
поэтому, теоретически ReadFile должен сразу их вернуть, т.е. не должно быть
состояния ERROR_IO_PENDING. Но, я не уверен что его не будет,
подозреваю, что все-таки иногда будет выполняться ветка GetOverlappedResult(),
что будет приводить к тормозам. В принципе, это можно попробовать проверить
экспериментально, сунуть сюда отладочный вывод..


Сейчас основные тормоза в Windows из-за операции write() с ожиданием,
т.е. как показано в коде в самом верху.

Так вот вопрос: а в *nix операции write/read сразу возвращают управление или нет?
(даже если дескриптор сконфигурен как неблокирующий и таймауты везде стоят по-нулям).

Если сразу - то я не буду заморачиваться с асинхронным I/O, и просто немного
подкорректирую Windows часть, в части операции write().

Как-то так...

Мож у кого есть что получше предложить? Прокомментировать?  Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
Страниц: 1 ... 58 59 [60] 61 62 ... 88   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.126 секунд. Запросов: 23.