LINUX.ORG.RU

Работа с двумя потоками в qt

 ,


1

2

Привет. В общем нужно два потока. Один поток это главный GUI, второй поток это управление внешними датчиками по шине rs485 назовем его mythreadbalancer. Нужно как-то организовать связь между ними думаю о сигналах и слотах.

Мне вот не ясно как лучше организовать код. Получается у меня будут другие окна не только main из которых мне тоже нужно отсылать и принимать данные потока mythreadbalancer. Получается что каждое окно будет принимать и передавать данные в поток mythreadbalancer. Не произойдут ли какие коллизии или еще что, у меня не достаточно опыта чтобы ответить на эти вопросы.

Ответ на: комментарий от rumgot

Думаю не получится. На время передачи данных по rs485 основной поток зависает, передает данные. По простому говоря передает побайтно один за одним байты, а скорость передачи 4800. Вот и получается время передачи одного байта 2,2 мили секунды хотим передать 32 байта получаем задержку 70,4 мили секунд, а если хотим передать 128 байт или делать опрос по бесконечному циклу. То главный поток зависнет намертво. Вот для этого и хочу сделать второй поток. Так сказать распределить задачи. Использую для передачи и приема данных libmodbus.

Alex_Golubev
() автор топика
Ответ на: комментарий от Alex_Golubev

Блин, у тебя есть qserialport, когда буфер будет готов ты получишь сигнал о готовности, просто получи данные и обработай, если время обработки слишком велико - то надо отправить его (обработчик не читалку данных) в отдельный поток. С записью тоже проблем быть не должно, потому как сначала все равно пихнёт в буфер обмена, а уж потом контроллер сам отправит данные, о чем пошлёт тоже сигнал. Если время работы твоего обработчика меньше 500 мс (а то и всех 800) то пользователь этого просто не заметит

Silerus ★★★★
()
Ответ на: комментарий от Alex_Golubev

Используй классы Qt для работы с Modbus протоколом. Чтение из порта производи по сигналу. Никаких зависаний не будет. Поток городить в данном случае нафиг не нужно.

rumgot ★★★★★
()
Ответ на: комментарий от Liz812

Господи ты боже мой. Мьютексы. Ребята, ну что вы городите. Это ведь потом кто-то читать будет еще менее опытный чем вы. Ну какие мьютексы, потоки. Ну что вы городите. Тут нужен один поток и чтение по сигналу. И все.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Сигналы и слоты вещь очень мутная. Кто даст гарантии что сигнал будет обязательно сразу обработан, а данные из датчиков не потеряются?

Liz812
()
Ответ на: комментарий от Liz812

Протокол модбас мастер—слейф. Мне не нужно понимать когда считать. Я даю команду на чтение в произвольный момент времени. И мне должен ответить слейф устройство. Вот и все.

Дал команду прочитать регистры. Получил ответ.

Мастер отправил запрос — получил ответ от слейва.

Alex_Golubev
() автор топика
Последнее исправление: Alex_Golubev (всего исправлений: 1)
Ответ на: комментарий от Alex_Golubev

Тогда все очень просто. Поток отправил запрос, считал данные, захватил мьютекс, поставил атрибут «данные готовы», освободил мьютекс. Другой поток захватил мьютекс увидел «данные готовы» забрал данные, сбросил атрибут, освободил мьютекс, дальше спокойненько эти данные обрабатывает.

Liz812
()
Ответ на: комментарий от Liz812

Сигналы и слоты вещь очень мутная.

Это когда ты не понимаешь, как они устроены.

Кто даст гарантии что сигнал будет обязательно сразу обработан, а данные из датчиков не потеряются?

Сигнал будет обработан сразу при условии нормальной архитектуры и отсутствии других затратных операций. Данные не потеряются, т.к. у последовательного порта есть буфер, а у протокола Modbus RTU есть контрольная сумма.

rumgot ★★★★★
()
Ответ на: комментарий от Liz812

данные из датчиков не потеряются?

Если источник и получатель существуют на момент вызова emit и получатель не будет удален до момента вызова слота все будет доставлено.

будет обязательно сразу обработан

Сразу - слово не имеющее смысла в данном контексте.

anonymous
()
Ответ на: комментарий от Liz812

Хорошо. Теорию по основам мьютексов ты знаешь. Но в данном случае это избыточно. В Qt данные между потоками лучше пересылать через сигналы-слоты.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

при условии нормальной архитектуры и отсутствии других затратных операций

Почему я обязана выполнить условие отсутствия затратных операций?

Liz812
()
Ответ на: комментарий от Liz812

Потому что в случае долгой затратной по времени операции (скажем копирование файла) другие события обрабатываться не будут. Но опять-таки система Qt очень гибкая и поэтому внутри каждой итерации длительной операции можно вызывать QCoreApplication::processEvents() для обработки других событий.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

долгой затратной по времени операции (скажем копирование файла) другие события обрабатываться не будут. внутри каждой итерации длительной операции можно вызывать QCoreApplication::processEvents()

Разве это не кривые костыли? А если длительная операция выполняется библиотечной функцией?

Liz812
()
Ответ на: комментарий от Liz812

Нет. Это гибкость библиотеки. Костыль - это городить поток с мьютексами, при том, что сама библиотека уже располагает средствами обмена данными между потоками.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Только мне очевидно что система слоты/сигналы в qt имеет фатальный недостаток в том, что время доставки сигнала призвольно и фиг его знает от чего оно зависит? А если у тебя эти датчики надо считывать сто раз в секунду? Сколько раз ты пропустишь?

В случае мьютекса выполнение контракта ГАРАНТИРУЕТСЯ операционной системой.

Liz812
()
Ответ на: комментарий от rumgot

Время принятия человеком визуальной информации принято считать 0.3 с + время пока человек примет решение 0.3 с и того 600 мс. В рекомендации по написанию интерфейсов есть рекомендация не превышать время реакцию приложение более чем 1с - это критический порог. Если мы не говорим об играх(где fps реально критично) - все что ниже 1 с нас устроит. Теперь о ТС - он собирается выводить данные с каких то датчик (я так понял) - если это будет изменение полей таблицы или изменение состояний виджетов - там не критично совсем. Если это будет вывод графиков - то там должна формироваться пачка данных - после чего перерисовывается вся область - так например сделано в программном интерфейсе к осциллографам (АКИП - которые не АКИП на самом деле), причем время там задается 1/2/3/4/5 и тд. секунд

Silerus ★★★★
()
Ответ на: комментарий от Liz812

время доставки сигнала призвольно и фиг его знает от чего оно зависит

У тебя операционная система реального времени - и поэтому у тебя никакое время не гарантировано.

А если у тебя эти датчики надо считывать сто раз в секунду? Сколько раз ты пропустишь?

Ты пробовала так делать? Или это фантазия? Как я уже писал выше - есть буфер у порта. И сто раз в секунду - это не так уж и много.

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от Alex_Golubev

Реализуй протокол modbus под себя на qt, там не так все сложно, учитывая сколько времени ты уже сношаешся с этим всем.

Silerus ★★★★
()
Ответ на: комментарий от Silerus

Извини, но херня. Если после нажатия на кнопку, весь интерфейс зависает на 600мс, это явно заметно и приносит дискомфорт.

rumgot ★★★★★
()
Ответ на: комментарий от Liz812

Я бы использовала мьютексы. Их специально придумали для этого.

Тебе лучше самой учиться, а не советы раздавать.

anonymous
()
Ответ на: комментарий от Liz812

выполнение контракта ГАРАНТИРУЕТСЯ операционной системой

Умничка, она и про контракты знает. Считаю, что зачет автоматом девочка заслужила. Какие будут мнения экспертов?

anonymous
()
Ответ на: комментарий от Alex_Golubev

Что бы разобраться в Qt и модбас. Потому как примера как работать с QThread есть везде, но ты все ломишься в открытую дверь. Я тебе ссылку даже дал, там задающий вопрос правильно отправляет класс в отдельный поток. На пальцах: надо создать класс потомок QObject в нем будет некая функция, которая будет постоянно опрашивать твои датчики по modbus. Там где создашь объект этого класса должен быть создан объект QThread. После этого выполняется метод moveToThread (это метод твоего класса, он унаследован от QObject). После этого происходит связывания сигналов старта потока и метода опроса функции, завершения работы и удаления объекта потока и вашего класса. После чего поток надо стартануть, вызвав метод start. Естественно общаться с этим потоком напрямую нельзя - значит либо в ваш класс надо передать указатель на переменные куда будет записан результат (здесь помним про критическую секцию и используем семафоры и мьютексы), либо ваш класс должен испускать сигнал с результатом работы, на который должен быть подписан приемник. В документации даже пример есть https://doc.qt.io/qt-5/qthread.html

Silerus ★★★★
()
Ответ на: комментарий от rumgot

У меня не дисктопное приложение. Я пишу программу для промышленного компьютера на который сначала нужно установить линукс, предварительно настроив .dts и написав кучу дров для управление переферии. И qt у меня из buildroot а в нем нет Modbus RTU. Есть только возможность включить libmodbus и не охота уже заморачиваться с подключением [quote] Повторяю еще раз: протокол Modbus RTU реализован в Qt[/quote] уже устал с настройкой. Сделаю из того что есть. Вот подумал о двух потоках. Сделал вроде два потока даже работают, но не знаю на сколько это правильно.

Alex_Golubev
() автор топика
Ответ на: комментарий от anonymous

Я полностью разделяю ваше мнение, коллега. Похоже она единственная, кто тут разбирается в мультипоточном программирование.

Uncle_Bobby
()
Ответ на: комментарий от rumgot

Все нормальные люди делают 2 почти всегда - один для морды, другой для логики, чтобы при вычислениях морда не тупила.

peregrine ★★★★★
()

Если есть возможность в libmodbus вытащить файловый дескриптор устройства, то можно обернуть его в QSocketNotifier, и обрабатывать сигнал activated.

anonymous
()
Ответ на: комментарий от Liz812

Нормально, бывает и хуже, я скажу более c переходом на qt5 лямбды стало можно использовать в место слотов (это они похоже готовятся к уходу от moc), кстати можно использовать не QThread - Qt Concurrent QFuture (аналог std::future) - и вот там можно и напрямую лямбдами.

Silerus ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.