Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: SektorCT от Декабрь 03, 2022, 19:39



Название: Класс для запуска и управления несколькими потоками
Отправлено: SektorCT от Декабрь 03, 2022, 19:39
Всем привет.
У меня имеется несколько классов которые надо запускать каждый в отдельном потоке.
И для управления я создал класс который и будет их запускать.
Но так как только учусь работать с потоками не совсем понимаю как они должны запускаться все в одном классе.
Нужно в одном классе запускать так как мне нужно данные передавать между всеми этими потоками.
Может кто посоветовать как это правильно реализовать? Буду признателен за простой абстрактный пример.


Название: Re: Класс для запуска и управления несколькими потоками
Отправлено: tux от Декабрь 03, 2022, 21:00
Можно попробовать использовать класс QtConcurrent
Есть довольно толковый пример http://itnotesblog.ru/note.php?id=148


Название: Re: Класс для запуска и управления несколькими потоками
Отправлено: sergek от Декабрь 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.");
 


Название: Re: Класс для запуска и управления несколькими потоками
Отправлено: SektorCT от Декабрь 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 связывается с каждым сигналом для каждого потока.
Для чего эти сигналы тут нужны и как они должны вызываться? Точнее в какой момент?


Название: Re: Класс для запуска и управления несколькими потоками
Отправлено: sergek от Декабрь 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");
...
 

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

ЗЫ Не стоит злоупотреблять цитированием сообщений, тем более, когда это и не требуется, - это плохой тон))


Название: Re: Класс для запуска и управления несколькими потоками
Отправлено: SektorCT от Декабрь 08, 2022, 01:41
В принципе я понял. Сейчас разбираюсь дял своей реализации.
Единственное у меня вопрос, у меня клиент запускается в потоке, клиент создает сокет и кидает потоку который уже организовывает конект.
И как понимаю методы read и write должны быть реализованы в классе самого потоке не в классе клиента?
Но вот когда поток я создаю для него то метод run overload запускается автоматом а мне надо так чтобы после какого то действия в приложении.
Могли бы правильный ход реализации подсказать?
С остальными потоками у меня порядок так как они просто данными обмениваются.
Спасибо.


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

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


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

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

Заранее благодарю за советы.