Форум программистов, компьютерный форум, киберфорум
C++ Qt
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.56/9: Рейтинг темы: голосов - 9, средняя оценка - 4.56
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
1

Разделение на потоки. запрос-ответ

04.11.2019, 16:10. Показов 1746. Ответов 26
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Реализовал класс в отдельном потоке

класс-работяга
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QString name= "", QObject *parent = nullptr);
public slots:
    void setText(const QString &value);
signals:
    void textIsSet(QString value);
};
обертка-поток
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class WorkThread:public QThread
{
    Q_OBJECT
public:
    explicit WorkThread (QString name = "",  QObject * const parent = nullptr );
 
protected:
    virtual void run () final;
public:
    Q_SLOT void textIsSet(QString value); /// для приема ответа от worker
    Q_SIGNAL void setText(const QString &value);/// передача данных в worker
    Q_SLOT void setText_outside(const QString &value); /// прием данных снаружи потока
    Q_SIGNAL void textIsSet_outside(QString value); /// отправка сигнала из потока
};
создание worker и соединение сигналов-слотов
C++ (Qt)
1
2
3
4
5
6
7
8
void WorkThread::run()
{
    Worker *worker = new Worker(m_name);
    worker->moveToThread(this);
    connect(this, &WorkThread::setText, worker, &Worker::setText);
    connect(worker, &Worker::textIsSet, this, &WorkThread::textIsSet);
    exec();
}
Использование
C++ (Qt)
1
2
3
4
thread1 = new WorkThread("thr1");
    connect(this, SIGNAL(setTextThr1(QString)), thread1, SLOT(setText_outside(QString)));
    connect(thread1, SIGNAL(textIsSet_outside(QString)), this, SLOT(settedText1(QString)));
    thread1->start();
Такой подход работает. И сигналы и слоты отрабатываются правильно.

Но делается это все для связи с прибором. Прибор может отвечать долго, т.к. измеряет (до 30 мин).
Как правильно общаться с классом worker (он же класс прибора) так, чтобы из MainWindow вызвать одну функцию measure, а внутри этой функции выполнился запрос к прибору на измерение и ожидание ответа? При этом чтобы GUI не зависал

примерно так
C
1
2
3
4
void MainWindow ::measure(){
 emit start_measure();
 wait measure_end
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.11.2019, 16:10
Ответы с готовыми решениями:

Epoll разделение на потоки
Здравствуйте, есть код сервера, с использованием асинхронных операций, при помощи epoll. (код...

Разделение на потоки работы с sfml
хочу написать программу с двумя потоками:один отвечает за GUI ,второй за логику,ожидание нажатия...

Разделение разбора xml-файла и обработка полученных данных на независимые потоки
файл разбирается при помощи StAX. разобранные данные записываются в ArrayList. для их обработки...

Python socket telnet, потоки и ответ сервера
Добрый день всем. Возник вопрос, рассматриваю как общаться с python через telnet, имею код: ...

26
фрилансер
5503 / 5098 / 1048
Регистрация: 11.10.2019
Сообщений: 13,360
04.11.2019, 16:39 2
ni_ko, я вот так обычно делаю

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
void WorkThread::run()
{
   QEventLoop m_EventLoop;
   for(;!isInterruptionRequested();)
   {
    bool bWasSome=m_EventLoop.processEvents(QEventLoop::AllEvents);
   
        ...//тут полная свобода действий. Можно ждать ответа хоть сутки, GUI не пострадает
   }
}
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
04.11.2019, 18:38 3
ni_ko, Зависит от того что внутри ф-ции.

Добавлено через 1 минуту
Но судя по
Цитата Сообщение от ni_ko Посмотреть сообщение
Прибор может отвечать долго, т.к. измеряет (до 30 мин).
Короткий ответ по предоставленной инфе - никак!

Добавлено через 1 минуту
C++ (Qt)
1
2
3
4
5
6
7
8
void WorkThread::run()
{
    Worker *worker = new Worker(m_name);
    worker->moveToThread(this);
    connect(this, &WorkThread::setText, worker, &Worker::setText);
    connect(worker, &Worker::textIsSet, this, &WorkThread::textIsSet);
    exec();
}
Этот код не верный, какого вообще "лезть" в QThread ? Наледоваться нет никакой необходимости.
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
04.11.2019, 21:03 4
Цитата Сообщение от Avazart Посмотреть сообщение
Этот код не верный, какого вообще "лезть" в QThread ? Наледоваться нет никакой необходимости.
Поддерживаю. Создал объект, переместил его в QThread (через moveToThread), соединил сигнал started QThread со слотом объекта и вызвал start для QThread. Стандартный прием.
0
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
05.11.2019, 10:13  [ТС] 5
ni_ko, я вот так обычно делаю
В этом случае ответа ждет оболочка над worker. В моем варианте это тоже работает. Вопрос был как дождаться ответа в другом потоке.

Добавлено через 2 минуты
Этот код не верный, какого вообще "лезть" в QThread ? Наледоваться нет никакой необходимости.
Чтобы экземпляр worker был создан уже в новом потоке и полностью ему принадлежал.
Или при moveToThread проихойдет то же самое?

Добавлено через 1 минуту
Цитата Сообщение от Avazart Посмотреть сообщение
Короткий ответ по предоставленной инфе - никак!
Т.е. единственное решение - это в GUI запоминать, что мы ждем ответа от worker и когда он пришел сбрасывать состояние ожидания?
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
05.11.2019, 12:11 6
Цитата Сообщение от ni_ko Посмотреть сообщение
как дождаться ответа в другом потоке.
Да как и всегда, в общем-просто ждите, установив, при необходимости, таймаут. И потом бросайте сигнал - или по получению результата, или по таймауту.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
05.11.2019, 13:08 7
Цитата Сообщение от ni_ko Посмотреть сообщение
Или при moveToThread проихойдет то же самое?
То же самое, главное правильно внутри работяги создавать объекты.
(желательно создавать объекты с лотах, а не в конструкторе работяги, так как конструктор выполнятся будет не в "самом потоке" а в месте создания.)
0
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
09.11.2019, 17:38  [ТС] 8
Как и советовали, избавился от переопределения run
Теперь реализую в WorkThread функцию подключения к железке.
Есть 2 варианта (показаны не полные функции, только суть):
C++ (Qt)
1
2
3
4
5
6
7
8
bool WorkThread::dev_conn_1(){
    emit device_connect(); /// этот сигнал ловится в worker и выполняется подключение
    QEventLoop m_EventLoop;
    m_EventLoop.processEvents(QEventLoop::AllEvents, 1000); /// даем время поработать текущему потоку для отработки очереди сигналов
    /// за это время должен был придти сигнал об изменившемся статусе worker
    /// проверяю переменную, сохраненную при обработке этого сигнала
    if(connect_success) return OK;
}
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
bool WorkThread::dev_conn_2(){
    emit serial_connect(state);
    QTime time;
    time.start();
    QEventLoop m_EventLoop;
    /// напрямую читаю статус. Т.е. вызываю функцию класса, >находящегося в другом потоке!<
    while(time.elapsed() < 1000 && !worker->is_connect()){
        m_EventLoop.processEvents(QEventLoop::AllEvents); /// чтобы не зависал GUI
    };
    if(worker->is_connect()) return OK;
}
Т.е. в первом варианте все взаимодействие идет через сигналы-слоты, а вот втором напрямую вызывается метод класса, находящегося в другом потоке. (указатель worker сохраняется в WorkThread)
Пока реализовал 2 способ, чтобы не плодить сигналов. Насколько это правильно? И как лучше?
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.11.2019, 18:47 9
Цитата Сообщение от ni_ko Посмотреть сообщение
Как и советовали, избавился от переопределения run
Теперь реализую в WorkThread функцию подключения к железке.
Советовали вообще избавится он наследования от QThread

Добавлено через 48 секунд
Цитата Сообщение от ni_ko Посмотреть сообщение
C++ (Qt)
1
m_EventLoop.processEvents(QEventLoop::AllEvents); /// чтобы не зависал GUI
Какой еще навиг GUI может быть во вторичном потоке?
Это гавнокод.
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
09.11.2019, 18:51 10
ni_ko, не совсем понятно, у вас железка одна и в каждый момент времени работа идет только с одним экземпляром или их несколько?
0
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
09.11.2019, 19:12  [ТС] 11
Цитата Сообщение от Avazart Посмотреть сообщение
Советовали вообще избавится он наследования от QThread
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class WorkController : public QObject
{
    Q_OBJECT
 
    QThread m_thread;
...
 
WorkController::WorkController(QString name, QObject * const parent)
{
    m_name = name;
    Worker *worker = new Worker(m_name);
    worker->moveToThread(&m_thread);
    connect(&m_thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
    connect(this, &WorkController::start_measure, worker, &Worker::start_measure);
    connect(worker, &Worker::measure_end, this, &WorkController::measure_end);
    m_thread.start();
}
Цитата Сообщение от Avazart Посмотреть сообщение
Какой еще навиг GUI может быть во вторичном потоке?
функция подключения вызывается из потока GUI, в классе WorkController, а он уже кидает сигнал в поток worker

Цитата Сообщение от insite2012 Посмотреть сообщение
у вас железка одна и в каждый момент времени работа идет только с одним экземпляром или их несколько?
железок будет несколько. Одновременно общение только с одной. Принцип общения одинаковый, но разные протоколы. Пока отрабатываю на одной. Потом будет для каждой свой набор классов worker-controller со своими особенностями
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.11.2019, 19:20 12
Как раз WorkController не обязательный класс им может быть класс формы.
Вопрос что в Worker классе.
0
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
09.11.2019, 19:20  [ТС] 13
мне так удобнее
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.11.2019, 19:23 14
Не говоря о том что поток лучше создавать динамически.
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
09.11.2019, 19:40 15
ni_ko, пара советов.
1. Локальную переменную m_thread сделайте полем класса, иначе по выходу из блока она будет уничтожена.
2. У вас, я так понимаю, есть обертка, которая уже создает потоки и в них помещает объекты. В ней есть необходимость? Возможно, проще непосредственно в GUI создавать объект-измеритель, двигать его в поток и пусть работает. Но вам виднее.
3.
Цитата Сообщение от ni_ko Посмотреть сообщение
Принцип общения одинаковый, но разные протоколы.
Тут вообще очень удобно, делаете базовый класс со всеми необходимыми сигналами, а потом под каждый протокол создаете наследника. Ну и класс-фабрику, создающий указатель на нужный тип и присваивающий его указателю на базовый. Недавно реализовывал нечто подобное, с применением шаблона Template Method. Очень удобный прием, на мой взгляд. В базовом классе только один реализованный слот, в котором вызываются другие функции (чисто виртуальные). И эти чисто виртуальные функции реализуются в наследниках. По указателю типа базового класса вызывается этот слот, а он уже вызывает чисто виртуальные функции (которые в каждом наследнике реализованы по разному).
Если надо, могу привести демонстрационный код такого приема.
0
3 / 3 / 0
Регистрация: 20.01.2015
Сообщений: 47
09.11.2019, 20:44  [ТС] 16
Цитата Сообщение от insite2012 Посмотреть сообщение
Если надо, могу привести демонстрационный код такого приема.
надо с фабриками раньше не работал, интересно посмотреть.
0
Эксперт С++
8385 / 6147 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
09.11.2019, 21:10 17
Да пусть сначала с потоками и сигнал-слотами разберется.
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
09.11.2019, 21:47 18
Цитата Сообщение от Avazart Посмотреть сообщение
пусть сначала с потоками и сигнал-слотами разберется.
Разберется, постепенно. Сюда код вставлять долго, я ему сейчас примерный каркас накидаю (один абстрактный класс работника и пара наследников), ну и простой виджет для демонстрации. А дальше пускай настраивает под свою логику работы.
0
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
09.11.2019, 22:11 19
ni_ko, вот архив с простым примером. Посмотрите, если что-то непонятно-напишете.
Вложения
Тип файла: rar WorkerDemo.rar (6.8 Кб, 5 просмотров)
1
1352 / 851 / 365
Регистрация: 26.02.2015
Сообщений: 3,799
10.11.2019, 20:09 20
Цитата Сообщение от Avazart Посмотреть сообщение
Советовали вообще избавится он наследования от QThread
https://habr.com/ru/post/150274/
0
10.11.2019, 20:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.11.2019, 20:09
Помогаю со студенческими работами здесь

Почему ответ на GET запрос из Python отличается от ответа на GET запрос из HTTP Analyzer
Добрый день. Делаю GET запрос из HTTP Analyzer Указываю только адрес запроса:...

Запрос и разделение записей
ковыряю внешнюю печатную форму. там есть запрос: ВЫБРАТЬ ЛимитыОтпуска.ЛимитОтпуска КАК Лимит...

Ответ на Get запрос
на сайте крутиться код &lt;html&gt; &lt;head&gt; &lt;title&gt;&lt;/title&gt; &lt;?php echo &quot;wtf&quot;; ?&gt; ...

Ответ на запрос
У меня есть переменная которая принимает данные: $data = $_POST; Мне нужно после того как я...

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

Ответ на запрос
Доброго времени суток ) Такой вопрос... Кто знает как при отправке сайту get или post запросв...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru