Russian Qt Forum
Ноябрь 23, 2024, 08:17
Добро пожаловать,
Гость
. Пожалуйста,
войдите
или
зарегистрируйтесь
.
Вам не пришло
письмо с кодом активации?
1 час
1 день
1 неделя
1 месяц
Навсегда
Войти
Начало
Форум
WIKI (Вики)
FAQ
Помощь
Поиск
Войти
Регистрация
Russian Qt Forum
>
Forum
>
Qt
>
Общие вопросы
>
Как разрулить потоки
Страниц:
1
2
3
[
4
]
5
Вниз
« предыдущая тема
следующая тема »
Печать
Автор
Тема: Как разрулить потоки (Прочитано 26551 раз)
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: Как разрулить потоки
«
Ответ #45 :
Июль 26, 2016, 08:53 »
Цитата: Sphynx от Июль 26, 2016, 08:22
Команды приходят во входной буфер, результат скидывается в выходной. Соответственно серия из команд ограничена только емкость буфера.
Это не протокол. Принципиально может ли устройство ответить с тем же уникальным кодом/ID что и посланная команда. Если да - можно посылать в любом (разумном) порядке.
Записан
Old
Джедай : наставник для всех
Offline
Сообщений: 4350
Re: Как разрулить потоки
«
Ответ #46 :
Июль 26, 2016, 08:56 »
Цитата: Sphynx от Июль 26, 2016, 08:22
Команды приходят во входной буфер, результат скидывается в выходной. Соответственно серия из команд ограничена только емкость буфера.
Вы сейчас говорите уже о слое бизнес-логики?
Записан
Sphynx
Гость
Re: Как разрулить потоки
«
Ответ #47 :
Июль 26, 2016, 09:52 »
Я не знаю что такое слой бизнес-логики ) Не надо ничего усложнять все до банальности просто. Устройство читает свой входной буфер, если там что-то есть, то выполняет и результат скидывает в выходной буфер.
Затолкать в буфер можно и одну и 2 и 10 команд, все равно они будут считываться и выполнятся последовательно.
Отслеживать ID запроса в железке теоретически можно, но придется перепиливать софт железки. По моему немного отошли от темы. Все что сейчас мешает это двойной вызов функции mcu->Read(); Я не знаю, может есть какие-то стандартные средства С++ чтобы не допускать такого. Либо раз уж это происходит, почему программа вешается при моем варианте решения. Как вообще правильно делить одну функция между разными потоками.
Записан
Bepec
Гость
Re: Как разрулить потоки
«
Ответ #48 :
Июль 26, 2016, 10:12 »
Ей богу, вам лучше написать тз и заказать программу под ваши нужды.
По идее вам надо начать с протокола, проанализировать, поменять или улучшить, соответственно перепрошить железяку под новый протокол(а мб и не нужно, кто знает), потом взять приведённые в теме коды и на его основе построить логику приема/передачи. А уже под эту логику сделать ui.
Записан
Old
Джедай : наставник для всех
Offline
Сообщений: 4350
Re: Как разрулить потоки
«
Ответ #49 :
Июль 26, 2016, 10:32 »
Цитата: Sphynx от Июль 26, 2016, 09:52
Я не знаю что такое слой бизнес-логики ) Не надо ничего усложнять все до банальности просто. Устройство читает свой входной буфер, если там что-то есть, то выполняет и результат скидывает в выходной буфер.
Затолкать в буфер можно и одну и 2 и 10 команд, все равно они будут считываться и выполнятся последовательно.
Отслеживать ID запроса в железке теоретически можно, но придется перепиливать софт железки. По моему немного отошли от темы. Все что сейчас мешает это двойной вызов функции mcu->Read(); Я не знаю, может есть какие-то стандартные средства С++ чтобы не допускать такого. Либо раз уж это происходит, почему программа вешается при моем варианте решения. Как вообще правильно делить одну функция между разными потоками.
Ничего в прошивке менять не нужно.
Покажите, для примера, несколько запросов к устройству с ответами и я покажу как это реализовать.
Например:
Запрос alive - ответ ok;
Запрос mode - ответ число обозначающее режим;
Запрос state - ответ bool (true - можно менять режим)
и т.д.
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: Как разрулить потоки
«
Ответ #50 :
Июль 26, 2016, 11:07 »
Цитата: Sphynx от Июль 26, 2016, 05:11
От kuzulis тоже не понимаю, запрос идет через слот, а как реализована обратная связь ?
Это самый простой/естественный вариант, неясно чем он не устраивает. Не организуем никаких ожиданий, не вызывает processEvents. Просто по таймеру получаем упр-е и смотрим есть (пришли) ли данные. Нет - уходим в событийный цикл, UI свободно. Пришли - разбираемся с ними. Все
А определить/идентифицировать на что пришел ответ так или иначе придется. Напр истек таймаут - а устройство прислало (запоздалый ответ).
Как посылать - тоже рассказали, самое простое складывать в очередь, а реальную посылку устройству делать когда получен (и обработан) ответ
Записан
Sphynx
Гость
Re: Как разрулить потоки
«
Ответ #51 :
Июль 26, 2016, 11:39 »
Команды шлются в текстовом виде, в устройстве крутится простейший интерпретатор, например:
ADC 6 IREF 5 3 2 AVCC 7 ;
Эту посылку можно рассматривать как 7 команд: запрашивает измерение с канала 6, установка опоры, измерение каналов 5 3 2 установка опоры, измерение канала 7.
Ответ будет последовательность слов каждое из которых оканчивается кодом $0D :
123 OK 234 345 456 OK 567
Соответственно послав строку
ADC 6 IREF 5 3 2 AVCC 7 ;
необходимо вычитать ровно 7 слов.
В моем случае это будет 7 последовательных вызовов mcu->Read();
Функция нарезает слова из буфера и возвращает признак:
m_OK - пришло сообщение "OK"
m_Num - пришло число
m_Timeout - превышено время ожидания.
и т.д.
Записан
kuzulis
Джедай : наставник для всех
Offline
Сообщений: 2812
Re: Как разрулить потоки
«
Ответ #52 :
Июль 26, 2016, 12:29 »
Цитировать
ADC 6 IREF 5 3 2 AVCC 7 ... как 7 команд
Моя парсилка видит только три:
* запрос ADC 6 -> ответ 123 OK (+CR)
* запрос IREF 5 3 2 -> ответ 234 345 456 OK (+CR)
* запрос AVCC 7 -> ответ 567 (ОК?) (+CR)
И в чем проблема?
1) суем в очередь три запроса
2) берем первый запрос ADC 6 из очереди и отсылаем его
3) приходит ответ 123 OK
4) мы определяем, соответствует ли данный ответ текущему запросу (запрос у нас еще в очереди)
5) если соответствует, то удаляем из очереди первый запрос, а ответ парсим и выводим в нужные контролы в UI
6) берем следующий запрос IREF 5 3 2 из очереди и отсылаем его
7) приходит ответ 234 345 456 OK
8 ) мы определяем, соответствует ли данный ответ текущему запросу (запрос у нас еще в очереди)
9) если соответствует, то удаляем из очереди первый запрос, а ответ парсим и выводим в нужные контролы в UI
и т.п.
если ответ не соответствует запросу - значит какая-то помеха была или что-то еще... тут или перепосылаем наш запрос опять,
или перезапускаем таймер-сторож, надеясь что ответ вот-вот может придет и пр... дальнейшее зависит от воображения..
Цитировать
оканчивается кодом $0D :
Это же ЕМНИП, CR, тогда вообще нет проблем с парсингом ответа: просто используем serial->canReadLine() && serial->readLine(),
все еще проще становится.
ЗЫ: Ну и в чем сложность то?
«
Последнее редактирование: Июль 26, 2016, 12:31 от kuzulis
»
Записан
ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
Re: Как разрулить потоки
«
Ответ #53 :
Июль 26, 2016, 13:49 »
У него почти отсутствует протокол, в том и проблема.
ADC 6 IREF 5 3 2 AVCC 7
Разбор на мой взгляд
ADC [номер канала] - запрос измерения с 6 канала (ответ цифра)
IREF - установка опоры (ответ OK/noOK)
(5 3 2 7 )[\d] - запрос данных с канала (ответ цифра)
AVCC - установка опоры (ответ OK/noOK)
Т.е. тут даже не пахнет нормальным протоколом, потому и возникают проблемы с логикой.
По хорошему на мой взгляд надо сделать стандартный кадр.
Что то типо
[признак начала кадра][команда][параметры команды]
Хотя и в таком виде можно спокойно написать свой менеджер.
PS и ещё 1 сообщение будет ниже. Для разделения мух и котлет.
Записан
Bepec
Гость
Re: Как разрулить потоки
«
Ответ #54 :
Июль 26, 2016, 14:10 »
Вам нужен менеджер с ожиданием ответа.
Пихаем в менеджер команды
ADC 6
IREF
5
3
2
AVCC 7
Он шлёт устройству, ждёт ответа.
Приходит ответ 123 OK 234 345 456 OK 567
Менеджер его парсит соответственно
123
OK
234
345
456
OK
567
И по кончанию парсинга испускает 7 (семь) сигналов о получении данных аля
Запрос Ответ
ADC 6 123
IREF OK
5 234
3 345
2 456
AVCC OK
7 567
В результате вам и думать не надо о том, что где то чёто вызывать, менеджер сам разрулит всё, вам нужно будет лишь их обработать.
Записан
Sphynx
Гость
Re: Как разрулить потоки
«
Ответ #55 :
Июль 26, 2016, 16:18 »
С разбором ответа проблем никаких и не возникает. Проблема возникает когда от от таймера ушла команда например
ADC 0 1 2 ;
и вызывается mcu->Read() для получения первого результата. И в этот момент от другого потока по нажатию на кнопку отправляется например
PORT $55 ;
и снова вызывается mcu->Read() для получения ответа.
Вариант с менеджером мы тут уже разобрали. Менеджер испустит 7 сигналов, только кому ? Запросы могут идти от различных кнопок.
Допустим получит менеджер число 123 и что ему с ним делать ? Кому его отправлять ?
Синтаксис запросов подразумевает что все что между
ADC
и
;
принадлежит к группе команд измерений.
ADC 6 IREF 5 3 2 AVCC 7 ;
эквивалентно
ADC 6 ; ADC IREF ; ADC 5 ; ADC 3 ; ADC 2 ; ADC AVCC ; ADC 7 ;
Поэтому если на запрос 3 пришел ответ 345, это абсолютно ни о чем не говорит.
Мне надо как-то заблокировать mcu->Read() для другого потока, пока первый поток не считает все данные.
Записан
kuzulis
Джедай : наставник для всех
Offline
Сообщений: 2812
Re: Как разрулить потоки
«
Ответ #56 :
Июль 26, 2016, 16:34 »
Блин, все же уже разжевали.
И опять-25, какие-то потоки, какие-то кнопки и пр. причем здесь кнопки, потоки вообще... каша-в-голове.
Ты понимаешь что такое очередь? Например, за колбасой:
1. Человеки в очереди - это таски/реквесты
2. Продавец - удаленный девайс
3. Первый чел протягивает 100р и грит: "Дайте краковской 100 гр" (это эквивалент запроса)
4. Продавец дает ему (это ответ)..
5. Чел покидает очередь
6. След чел дает 1рубь.. дайте московской 10 кг...
7. У продавца ступор и когнитивный диссонанс (это таймаут)
8. Продавец отвечает: "да пшел ты с рублем" - это ошибка.
9. Чел или уходит из очереди или пытается состав 1000р повторить попытку..
Я умываю руки.
«
Последнее редактирование: Июль 26, 2016, 16:42 от kuzulis
»
Записан
ArchLinux x86_64 / Win10 64 bit
Bepec
Гость
Re: Как разрулить потоки
«
Ответ #57 :
Июль 26, 2016, 16:35 »
Вы опять не догоняете.
Выбросьте из головы своей свою mcu->read. Забудьте о вызове этого метода, его нет, не будет и никогда не было.
У вас 1(один) объект порта. У вас 1(один) менеджер. У вас 2(два) получателя/просителя/работника/потока.
3 сущности:
Поток 1
Поток 2
Менеджер
Поток 1 пишет в менеджер ADC 0 1 2.
Список запросов менеджера:
0 Поток 1 запросил "ADC 0 1 2"
Поток 2 пишет в менеджер PORT $55.
Список запросов менеджера:
0 Поток 1 запросил "ADC 0 1 2"
1 Поток 2 запросил "PORT $55"
Менеджер начинает работу. Посылает устройству запрос 0 и запускает таймер на ответ
Если пришли данные - вынимает из запрос 0 отправителя и шлёт ему отвёт "122 155 166"
Если данных нет и таймер вышел, то - вынимает из запрос0 отправителя и шлёт ему ошибку "Запрос ADC 0 1 2 нет ответа"
В результате удаляет первый элемент списка запросов.
Список запросов менеджера:
0 Поток 2 запросил "PORT $55"
Дальше аналогично.
У вас в результате оба потока получили данные(или ошибку). Мало того, потоков может быть неограниченное число, менеджеру без разницы сколько их.
PS я конечно опустил многие детали вроде разделение данных и ошибок, вроде парсинга структур и проверки данных на соответствие, добавлении, удаления запросов, обработку ошибок порта и прочее. Но это уже несущественно.
PPS на правах рекламы - за энную сумму могу вам написать программу, проконсультировать, разъяснить.
«
Последнее редактирование: Июль 26, 2016, 16:36 от Bepec
»
Записан
kuzulis
Джедай : наставник для всех
Offline
Сообщений: 2812
Re: Как разрулить потоки
«
Ответ #58 :
Июль 26, 2016, 16:43 »
Млин, да не нужны тут потоки.. ну вообще не нужны!
Записан
ArchLinux x86_64 / Win10 64 bit
Sphynx
Гость
Re: Как разрулить потоки
«
Ответ #59 :
Июль 26, 2016, 16:49 »
Не обижайтесь, я правда не понимаю что вы мне пытаетесь разжевать.
Можно конкретней, пусть будут 3 кнопки A B C. По нажатию на кнопки необходимо выполнять определенный сценарий из команд.
Опишите пожалуйста не нижние функции обработчика парсера менеджера и тд. а верхние.
То есть прям конкретно пусть по нажатии кнопки А необходимо:
Установить порт
PORT DDR $FF 0 ;
Измерить канал
ADC 5 ;
если значение меньше 100 то установить порт
PORT $FF ;
Как будет выглядеть эта процедура прям вот конкретно внутри MainWindow::on_pushButton_clicked()
Записан
Страниц:
1
2
3
[
4
]
5
Вверх
Печать
« предыдущая тема
следующая тема »
Перейти в:
Пожалуйста, выберите назначение:
-----------------------------
Qt
-----------------------------
=> Вопросы новичков
=> Уроки и статьи
=> Установка, сборка, отладка, тестирование
=> Общие вопросы
=> Пользовательский интерфейс (GUI)
=> Qt Quick
=> Model-View (MV)
=> Базы данных
=> Работа с сетью
=> Многопоточное программирование, процессы
=> Мультимедиа
=> 2D и 3D графика
=> OpenGL
=> Печать
=> Интернационализация, локализация
=> QSS
=> XML
=> Qt Script, QtWebKit
=> ActiveX
=> Qt Embedded
=> Дополнительные компоненты
=> Кладовая готовых решений
=> Вклад сообщества в Qt
=> Qt-инструментарий
-----------------------------
Программирование
-----------------------------
=> Общий
=> С/C++
=> Python
=> Алгоритмы
=> Базы данных
=> Разработка игр
-----------------------------
Компиляторы и платформы
-----------------------------
=> Linux
=> Windows
=> Mac OS X
=> Компиляторы
===> Visual C++
-----------------------------
Разное
-----------------------------
=> Новости
===> Новости Qt сообщества
===> Новости IT сферы
=> Говорилка
=> Юмор
=> Объявления
Загружается...