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

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

Страниц: 1 ... 5 6 [7]   Вниз
  Печать  
Автор Тема: Работа из QSerialPort из разных потоков  (Прочитано 46816 раз)
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #90 : Март 24, 2017, 12:00 »

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

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alechin
Гость
« Ответ #91 : Март 24, 2017, 12:10 »

1. Переключение между потоками это затраты.
переключений между потоками нет. Поток "спит" на WaitFor..Objects ожмдая своих WaitableTimer, Event и прочее.
у меня, например, суммарная нагрузка от потоков, например двух GPS, не превышает тысячной процента! Поток получает управление один раз в секунду при приеме терминального символа и все. А поток отслеживания состояния светофор и стрелок и того реже - только когда эти переключения происходят. Откуда переключения?
 
2. Мютексы это затраты
никаких мьютексов. критические секции. она не является объектом ядра. затраты = 0.
для устранения взаимных блокировок одно строгое правило: внутри критической секции никаких других критических секций!

3. Усложнение архитектуры
внешний исходный код упрощается очень сильно. например работа с принтером в основном потоке:
POS_Printer printer("COM3");
(да - динамических объектов стараемся избегать для исключения сюрпризов с веделением памяти, все что нужно выделается сразу чтобы сразу знать что "непойдет", а не потом, когда уже поздно).
if(POS_Printer.Start() != true)
{
// все плохо! думаем что дальше.
}

где надо печатать:
if(printer.Get_State(&state) != true)
{
// все плохо! думаем что дальше.
}
else
{
  if(state.OffLine())....
  if(state.PaperEnd()).....
  настраиваем принтер..
  // с принтером все хорошо.
  // кидаем в принтер кучу заданий.
  // по первому заданию он сразу в фоне начинает печатать.
  for(;Подмигивающий printer.AddTask();
}

все "прозрачно" - все использование в одном экране! Никаких "прыганий" по исходнику.

4. Большая вероятность допуска ошибки, которую крайне тяжело будет вычленить.
ну это на совести программиста. Ошибку можно и на ровном месте допустить.
а при наличии уже отработанного класса его использование резко упрощается, вероятность ошибки минимальна (см. приведенный выше псевдо код - в чем там можно ошибиться?)

По поводу загрузки на 100% - загружает не канал, а обработка данных - обработка должна уметь правильно рулить ресурсами и не допускать такого поведения.
какая разница что загружает? мне при приеме пакета надо парсить = искать флаги, считать контрольную сумму, если не совпала - искать новый флаг, считать новую сумму. и так по всему буферу приема по каждому принятому байта. А загружало даже не это: периодически происходили ошибки порта, типа прием BREAK, ошибка parity и прочее. По каждой ошибке пытались что-то сделать, переинициализировать порт и прочее.......
Записан
Alechin
Гость
« Ответ #92 : Март 24, 2017, 12:24 »

дополню.
3. Усложнение архитектуры
4. Большая вероятность допуска ошибки, которую крайне тяжело будет вычленить.
тестируется написанный класс без привязки к системе. Т.е. классу все равно в какой системе он будет "крутиться".
т.е. если класс протестирован - он будет работать. Ошибка может быть только в использовании класса. Но обычно классы предоставляют минимум довольно простого интерфейса, что минимизирует вероятность ошибки. пример: класс GPS-приемника. Интерфейс класса только: конструктор, методы Start/Stop, методы доступа к потокозаищенным переменным state и cur_time. ну еще может метод ReStart. все. основной поток создает экземпляр, запускает.
те пользователи (потоки), которым надо узнать время читает значение time там где им нужно и когда им нужно.
Один из потоков контролирует работу системы (это может быть и GUI поток), если он видит что GPS.state "неправильный" - решает что дальше, сделать ReStart, открыть/закрыть или прочее.
сложность использования = примитив, поэтому
вероятность ошибки = 0.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #93 : Март 24, 2017, 12:31 »

А если я этот класс помещу в один поток и одновременно дерну разные его методы из n других потоков?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alechin
Гость
« Ответ #94 : Март 24, 2017, 12:44 »

А если я этот класс помещу в один поток и одновременно дерну разные его методы из n других потоков?
конкретно для класса GPS методы Start и Stop дергать не кто не будет. хотя ничто не запрещает это сделать, согласен.
с другой стороны метод старт не перезапускает уже запущенный поток. поэтому думаю ничего не произойдет.
совместно используются только данные. например time для GPS. читать его может кто угодно и откуда угодно - критическая секция у time разграничит доступ.
Для более сложных классов, например радиомодем все сделано через очереди. Если кто-то хочет передать что-то, он вызывает метод Put_Request_to_Quque. запрос кладется в потокзащищенную очередь с событием. Если поток спит - событие будит его и он начинает его передачу в нужном тайм-слоте.
с другой стороны у меня в системе архитектура несколько другая. например есть радар в тупике, он каждын 100 мсек кладет в свою потоказищенную очередь новое измеренное значение и взводит событие наличия новых данных. Класс самостоятельный, ему все-равно кто будет пользоваться его данными и будет ли вообще кто-то. Он тупо набивает очередь пока не придет команда остановиться или сбросить очередь. Есть класс "тупиковый путь" - ему нужны данные радара. Он ждет их на событии очереди данных радара. Как только у связанного с ним радара в очереди появляются новые данные (см. выше) он пробуждается, выбирает данные из очереди (с удалением или без - зависит от логики работы) что-то с ними делает, пересчитывает по критериям и прочее, сохраняет результат своей обработки в своей очереди обработанных данных . Класс радиомодема так-же самостоятельный, он четко с заданной синхрограммой пробегает по всем классам путей, на которых есть зарегистрированный им поезда, выбирает из них последнее значение и отправляет на поезд в нужном тайм-слоте. Т.е. взаимодействие практически только по данным. все классы независимы. им наплевать кто вокруг них, кто пользуется его данными и зачем. Т.е. фактичеки никаких методов между классами нет. Каждый класс статический, поэтому "пропасть" он не может. Например, если что-то не так с радаром (физически или классом) - просто перестает обновляться его очередь данных. класс пути видя что новых данных нет -начинает "беспокоится" извещая класс контроля системы что с его радаром что-то нет.....
сильно упрощенно все выглядит так.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #95 : Март 24, 2017, 12:49 »

Я тебя на другое хотел вывести - любое АПИ основанно на контрактах. Если ты не выполняешь контракт, ты получаешь UB. Так вот, контракт у Кьюта - не дергать методы QObject из других потоков. Если тебе такой контракт не подходит, не используй QSerialPort, а напиши свою обертку над системными вызовами или возьми другое решение. И не надо осуждать такой контракт, так как у всех остальных все отлично работает, достаточно только соблюдать условия. Как уже говорили выше, со своим уставом в чужой монастырь лучше не лезть.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alechin
Гость
« Ответ #96 : Март 24, 2017, 12:51 »

Я тебя на другое хотел вывести - любое АПИ основанно на контрактах. Если ты не выполняешь контракт, ты получаешь UB. Так вот, контракт у Кьюта - не дергать методы QObject из других потоков. Если тебе такой контракт не подходит, не используй QSerialPort, а напиши свою обертку над системными вызовами или возьми другое решение. И не надо осуждать такой контракт, так как у всех остальных все отлично работает, достаточно только соблюдать условия. Как уже говорили выше, со своим уставом в чужой монастырь лучше не лезть.
по моему от Qt мы давно отошли - мы обсуждаем что "иметь кучу потоков ооочень плохо!". а я пытаюсь понять почему.
как надо делать на Qt уже понял 3 страницы назад Улыбающийся
потому и просил закрыть тему, так как последние минимум 3 страницы не по теме.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #97 : Март 24, 2017, 20:11 »

Нет, там более сложная архитектура. А это просто наколенный пример. Улыбающийся
Принципиальные отличия есть? В двух словах.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #98 : Март 24, 2017, 20:18 »

хорошая тема новичка, побольше бы таких
а то обычно спросят всякую фигню и еще за ответ поблагодарят )
Записан
Alechin
Гость
« Ответ #99 : Март 30, 2017, 12:56 »

А еще если можно вопрос в продолжение: как прервать запущенную операцию записи или чтения?
у меня принтер работает с XON/OFF. когда он присылает XOFF передача останавливается и дальше я ничего не могу сделать если принтер не удается "оживить".
Принтер поддерживает запросы и команды вне буфера данных, т.е. когда его буфер заполнен он присылает XOFF, при этом я могу послать ему запрос данных что бы узнать, что его остановило. или послать ему команду сброса.
если я это делаю при "приостановленной" передаче - у меня происходит critical error.
по хорошему мне надо иметь возможность хотя бы просто прервать запущенную операцию записи.
Записан
grego812
Гость
« Ответ #100 : Апрель 14, 2017, 17:30 »

я не "вилосипедю". мои системы управляют в реальном времени движением поездов (велком ту ПостЭЦ пассажирской станции москва-ленинградская и можно посмтреть в реальном времени как управляется осаживание поездов в тупики.
Прошу прощения, но позволю себе немного оффтопа. В реальном времени движением поездов управляют системы СЦБ, исполнительная часть которых (т.е. которая за безопасность отвечает) сделана на здоровенных реле и ещё очень нескоро будет заменена на электронные, я конечно же говорю про РФ. Вы скорее всего занимаетесь наборной частью и отображением поездной ситуации на мониторы дежурного по станции. При этом даже если компоктир дежурного взорвётся, у него всегда есть возможность перейти на резервное управление с древнего пульта.
Записан
Alechin
Гость
« Ответ #101 : Апрель 16, 2017, 14:48 »

нет, вы в чем-то правы. но не совсем. есть такая система Призма, которая контролируем заезд поезда в тупиковый путь. Там как раз все в реальном времени. Если по расчетному тормозному пути поезд не успевает остановится - его принудительно тормозят по радиоканалу. А тормозной путь рассчитывается по данным установленного в тупике радара (см. перроны Ленинградского вокзала - там радары стоят) или по данным лазерного дальномера (см. Павелецкий и Ярославский вокзалы).
т.е. если система "задумалась" не важно по какой причине - тормозить состав будет уже поздно. А случаи "выхода" состава на перрон были неоднократно (как просто удар в тупиковую призму электрички, так и с "выходом" крайнего вагона на перрон).
Записан
Страниц: 1 ... 5 6 [7]   Вверх
  Печать  
 
Перейти в:  


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