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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Класс для запуска и управления несколькими потоками  (Прочитано 2697 раз)
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« : Декабрь 03, 2022, 19:39 »

Всем привет.
У меня имеется несколько классов которые надо запускать каждый в отдельном потоке.
И для управления я создал класс который и будет их запускать.
Но так как только учусь работать с потоками не совсем понимаю как они должны запускаться все в одном классе.
Нужно в одном классе запускать так как мне нужно данные передавать между всеми этими потоками.
Может кто посоветовать как это правильно реализовать? Буду признателен за простой абстрактный пример.
Записан
tux
Global Moderator
Бывалый
*****
Offline Offline

Сообщений: 404



Просмотр профиля
« Ответ #1 : Декабрь 03, 2022, 21:00 »

Можно попробовать использовать класс QtConcurrent
Есть довольно толковый пример http://itnotesblog.ru/note.php?id=148
Записан

sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


Просмотр профиля
« Ответ #2 : Декабрь 03, 2022, 21:52 »

Например, так:
Код
C++ (Qt)
class CCoreServer : public QObject
{
   Q_OBJECT
private:private:
   CServicePolling  polling;
   CServiceArchives archiving;
   CServiceRules    rules;    
   CServiceTransmit transmission;
 
   QThread pollingThread;    
   QThread archivingThread;  
   QThread ruleThread;        
   QThread transmissionThread;
 
...
 
CCoreServer::CCoreServer(QObject *parent) : QObject(parent),
   polling(this),
   archiving(this),
   rules(this),
   transmission(this)
{
...
 
   polling.moveToThread(&pollingThread);
   QObject::connect(this, &CCoreServer::servicePollingSig, &polling, &CServicePolling::serviceRunSlot, Qt::BlockingQueuedConnection);
   pollingThread.setObjectName("polling");
   pollingThread.start(QThread::HighPriority);
   qInfo ("Polling thread started.");
 
   archiving.moveToThread(&archivingThread);
   QObject::connect(this, &CCoreServer::serviceArchiveSig, &archiving, &CServiceArchives::serviceRunSlot, Qt::BlockingQueuedConnection);
   archivingThread.setObjectName("archiving");
   archivingThread.start();
   qInfo ("Archiving thread started.");
 
   rules.moveToThread(&ruleThread);
   QObject::connect(this, &CCoreServer::serviceRuleSig, &rules, &CServiceRules::serviceRunSlot, Qt::BlockingQueuedConnection);
   QObject::connect(this, &CCoreServer::loadRuleSig,    &rules, &CServiceRules::loadRulesSlot);
   ruleThread.setObjectName("rules");
   ruleThread.start();
   qInfo ("Rules thread started.");
 
   transmission.moveToThread(&transmissionThread);
   QObject::connect(this, &CCoreServer::serviceTransmissionSig, &transmission, &CServiceTransmit::serviceRunSlot, Qt::BlockingQueuedConnection);
   transmissionThread.setObjectName("transmission");
   transmissionThread.start(QThread::LowPriority);
   qInfo ("Transmission thread started.");
 
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #3 : Декабрь 03, 2022, 23:01 »

Например, так:
Код
C++ (Qt)
class CCoreServer : public QObject
{
   Q_OBJECT
private:private:
   CServicePolling  polling;
   CServiceArchives archiving;
   CServiceRules    rules;    
   CServiceTransmit transmission;
 
   QThread pollingThread;    
   QThread archivingThread;  
   QThread ruleThread;        
   QThread transmissionThread;
 
...
 
CCoreServer::CCoreServer(QObject *parent) : QObject(parent),
   polling(this),
   archiving(this),
   rules(this),
   transmission(this)
{
...
 
   polling.moveToThread(&pollingThread);
   QObject::connect(this, &CCoreServer::servicePollingSig, &polling, &CServicePolling::serviceRunSlot, Qt::BlockingQueuedConnection);
   pollingThread.setObjectName("polling");
   pollingThread.start(QThread::HighPriority);
   qInfo ("Polling thread started.");
 
   archiving.moveToThread(&archivingThread);
   QObject::connect(this, &CCoreServer::serviceArchiveSig, &archiving, &CServiceArchives::serviceRunSlot, Qt::BlockingQueuedConnection);
   archivingThread.setObjectName("archiving");
   archivingThread.start();
   qInfo ("Archiving thread started.");
 
   rules.moveToThread(&ruleThread);
   QObject::connect(this, &CCoreServer::serviceRuleSig, &rules, &CServiceRules::serviceRunSlot, Qt::BlockingQueuedConnection);
   QObject::connect(this, &CCoreServer::loadRuleSig,    &rules, &CServiceRules::loadRulesSlot);
   ruleThread.setObjectName("rules");
   ruleThread.start();
   qInfo ("Rules thread started.");
 
   transmission.moveToThread(&transmissionThread);
   QObject::connect(this, &CCoreServer::serviceTransmissionSig, &transmission, &CServiceTransmit::serviceRunSlot, Qt::BlockingQueuedConnection);
   transmissionThread.setObjectName("transmission");
   transmissionThread.start(QThread::LowPriority);
   qInfo ("Transmission thread started.");
 

Спасибо за пример.
Хотел бы уточнить, у основного класса CCoreServer в connect связывается с каждым сигналом для каждого потока.
Для чего эти сигналы тут нужны и как они должны вызываться? Точнее в какой момент?
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


Просмотр профиля
« Ответ #4 : Декабрь 04, 2022, 13:17 »

Эти сигналы (servicePollingSig, serviceArchiveSig и т.д.) я оставил для примера, чтобы вы помнили, что межпотоковое взаимодействие осуществляется, как правило, с помощью этого механизма.
В моем случае объекты polling, archiving и т.д. выполняют каждый свою задачу (опрос устройств, создание долговременного архива данных и т.д.), работают каждый со своей периодичностью по таймеру. Поскольку таймер должен создаваться в том потоке, в котором он работает, то для запуска используются упомянутые выше сигналы. Вызываются они тогда, когда это нужно по ходу выполнения программы. Например, у меня - при запуске сервера, после того, как все объекты созданы, распиханы по потокам, прочтена конфигурация:
Код
C++ (Qt)
void CCoreServer::startServices() {
...
   if(COptions::autoPolling)
       emit servicePollingSig(true);
   else
       qInfo("CoreServer: service of polling disabled.");
 
   if(COptions::autoArchiving)
       emit serviceArchiveSig(true);
...
 
Если ваши классы что-то там делают, а результат их деятельности (например, какие-нибудь данные) потребляются в каком-нибудь другом потоке, то придется создать еще одно соединение сигнал-слот, через которое будете отдавать эти данные.

Если эти данные будут представлять собой объекты каких-нибудь ваших классов, то эти классы нужно будет зарегистрировать в метаобъектной системе Qt, например, так:
Код
C++ (Qt)
Q_DECLARE_METATYPE(CRequestArgs)
...
{
   if(!QMetaType::isRegistered(QMetaType::type("CRequestArgs")))
       qRegisterMetaType <CRequestArgs>    ("CRequestArgs");
...
 

В общем, там еще очень много интересного Подмигивающий Поэтому присматривайтесь к сообщениям компилятора.

ЗЫ Не стоит злоупотреблять цитированием сообщений, тем более, когда это и не требуется, - это плохой тон))
« Последнее редактирование: Декабрь 04, 2022, 13:24 от sergek » Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #5 : Декабрь 08, 2022, 01:41 »

В принципе я понял. Сейчас разбираюсь дял своей реализации.
Единственное у меня вопрос, у меня клиент запускается в потоке, клиент создает сокет и кидает потоку который уже организовывает конект.
И как понимаю методы read и write должны быть реализованы в классе самого потоке не в классе клиента?
Но вот когда поток я создаю для него то метод run overload запускается автоматом а мне надо так чтобы после какого то действия в приложении.
Могли бы правильный ход реализации подсказать?
С остальными потоками у меня порядок так как они просто данными обмениваются.
Спасибо.
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 872


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


Просмотр профиля
« Ответ #6 : Декабрь 08, 2022, 14:07 »

Код:
Единственное у меня вопрос, у меня клиент запускается в потоке, клиент создает сокет и кидает потоку который уже организовывает конект.
Не понял про "кидает" и про "коннект". Попробуйте это сформулировать другим языком, используя терминологию Qt.
Если же вы имеете в виду соединение сигнал-слот, то его правильнее осуществлять в клиенте.

Код:
И как понимаю методы read и write должны быть реализованы в классе самого потоке не в классе клиента?
Но вот когда поток я создаю для него то метод run overload запускается автоматом а мне надо так чтобы после какого то действия в приложении.
Что за read, write? Это обработчики сокета?
Судя по всему, вы наследуете QThread. Это не очень хороший способ использования потока. Я вам дал пример, в котором нужный объект передается объекту потока, а запуск выполнения потока вы можете осуществлять, когда вам нужно.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #7 : Декабрь 08, 2022, 18:58 »

Код:
Что за read, write? Это обработчики сокета?
Судя по всему, вы наследуете QThread. Это не очень хороший способ использования потока. Я вам дал пример, в котором нужный объект передается объекту потока, а запуск выполнения потока вы можете осуществлять, когда вам нужно.

В общем, имеется клиент, и я его хочу в поток кинуть. read и write это методы сокета классического() так как мне надо проверять что прилетает или какой размер и ждать пока все не прилетит, какой тип пакета. По этому эту часть мне надо это таким путем делать.
Нашел в инете несколько примеров, и в них я запутался как правильно делать. В одном клиент классу наследованному от QThread передает QTcpSocket и уже поток у себя запускает. Другой пример показывает передачу через moveToThread класса клиент. В общем запутался.
Почему наследоваться от QThread не хороший способ?

Заранее благодарю за советы.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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