Политика конфиденциальностиКонтактыО сайтеОтзывыGitHubDonate
© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB
17 апреля 2019 г. 7:58

Потоки. Параллельные действия.

QTableWidget, QThread, threads

Доброго времени суток!

Нужен совет по много поточности. Есть вот такая вот табличка.

Столбец статуc хотелось бы получать в потоке для всех записей (АЗС). Для одной записи я реализовал получение статуса сервера базы данных.

Вопрос в том как делать это для всех записей, количество записей до 200 чтобы для каждой записи это делалось в потоке.


Реализация получения статуа в потоке

CheckAzsStatus *checkStatus = new CheckAzsStatus(modelConnections->data(modelConnections->index(0,0,QModelIndex())).toInt(),
                                                     modelConnections->data(modelConnections->index(0,1,QModelIndex())).toString());
    QThread *thread = new QThread(this);

    checkStatus->moveToThread(thread);


    connect(thread,&QThread::started, this, &ShowPage::slotStartExecute,Qt::DirectConnection);
    connect(thread,&QThread::started, checkStatus, &CheckAzsStatus::slotCheckAzsStatus,Qt::DirectConnection);


    connect(checkStatus,&CheckAzsStatus::signalSendResult,this,&ShowPage::slotGetAzsStatus);

    connect(checkStatus,&CheckAzsStatus::finished,this,&ShowPage::slotStopExecute);
    connect(checkStatus,&CheckAzsStatus::finished,thread,&QThread::quit);
    connect(checkStatus,&CheckAzsStatus::finished,checkStatus,&CheckAzsStatus::deleteLater);
    connect(thread,&QThread::finished, thread, &QThread::deleteLater);

    thread->start();


}


void ShowPage::slotStartExecute()
{
    qInfo(logInfo()) << Q_FUNC_INFO << QDateTime::currentDateTime().toString("dd-MM-yyyy hh:mm:ss.zzz") <<  "Thread started";
}

void ShowPage::slotStopExecute()
{
    qInfo(logInfo()) << Q_FUNC_INFO << QDateTime::currentDateTime().toString("dd-MM-yyyy hh:mm:ss.zzz") <<  "Thread stoped";
}

void ShowPage::slotGetAzsStatus(bool res)
{
    if(res){
        ui->tableWidget->item(0,2)->setText("ON LINE");
    } else {
        ui->tableWidget->item(0,2)->setText("OFF LINE");
    }

}

Реализация проверки checkazsstatus.h

#ifndef CHECKAZSSTATUS_H
#define CHECKAZSSTATUS_H

#include <QObject>

class CheckAzsStatus : public QObject
{
    Q_OBJECT
public:
    explicit CheckAzsStatus(int term, QString ip, QObject *parent = nullptr);

signals:
    void signalSendResult(bool status);
    void finished(int term);

public slots:
    void slotCheckAzsStatus();
private:
    QString m_serverName;
    int m_terminalID;
};

#endif // CHECKAZSSTATUS_H

checkazsstatus.cpp

#include "checkazsstatus.h"
#include "LoggingCategories/loggingcategories.h"
#include <QTcpSocket>

CheckAzsStatus::CheckAzsStatus(int term, QString ip, QObject *parent) : QObject(parent)
{
    m_serverName = ip;
    m_terminalID = term;
    qInfo(logInfo()) << "IP" << m_serverName << "Terminal" << m_terminalID;
}

void CheckAzsStatus::slotCheckAzsStatus()
{

    bool status;
    QTcpSocket *tcpSocket = new QTcpSocket();
    tcpSocket->connectToHost(m_serverName, 3050);
    if(tcpSocket->waitForConnected(30000)){
        status = true;
    } else {
        status = false;
    }
    emit signalSendResult(status);
    emit finished(m_terminalID);
}

Буду благодарен за любою помошь.

Возврат 10% от суммы заказа отеля на Booking
Возврат 10% от суммы заказа отеля на Booking
Предлагаем ссылку с 10% возвратом от суммы заказа при бронировании отеля через Booking
25

как то немного сомбурно выглядит описание. вы хотите получать статус 200 обьектов в отдельном потоке или для каждого свой поток? я так понял описание обьектов находится в бд?

0

Простите за сумбурность. :-) Да для каждого объекта в своем потоке, поскольку связь с объектами оставляет желать лучшего. При наличии связи с обектом на базе АЗС выполняется SQL запрос на получении информации ( в данном случае наименование видов топлива на АЗС) Описание объектов в объекте QSqlTableModel, получаемой из базы данных.

0

как вариант (работать буде при неограниченном колличестве обьектов). добавьте в класс проверки статуса, полную реализацию проверки с сигналами и тд, только в конектах можно завязать не на слот класа а на новый сигнал, после в основном классе, можно сделать запрос в БД на получение данных о ваших обьектах (ID, IP и тд), и при разборе этих данных создавайте обьект проверки и сделайте перепривязку сигналов, при создании можете его пихнуть в вектор например, и перебором вектора пихать каждый обьект в отдельный поток для проверки(например QtConcurrent), а полученый результат через сигналы парсить

0

Придется в каждом потоке создавать свое соединение с БД: документация Qt

0

а смысл? соеденение с БД можно сделать глобальным и в потоке при запросе просто делать указание QSqlQuery query(str,db) документация

0

Алексей, данные об объектах я получаю.

    modelConnections = new QSqlQueryModel();
//    QSqlDatabase db = QSqlDatabase::database();
    QString inStr = m_listTerminals.join(",");


    QString strSQL = QString("SELECT c.TERMINAL_ID, c.SERVER_NAME, c.DB_NAME, c.CON_PASSWORD from CONNECTIONS c "
                             "WHERE c.TERMINAL_ID IN (%1) and c.CONNECT_ID = 2 "
                             "ORDER BY c.TERMINAL_ID")
            .arg(inStr);
    qInfo(logInfo()) << "SQL" << strSQL;
    modelConnections->setQuery(strSQL);

    qInfo(logInfo()) << "Model Row Count" << modelConnections->rowCount();

    ui->tableWidget->clearContents();
    ui->tableWidget->clear();

    ui->tableWidget->setColumnCount(COLUMN_COUNT);
    ui->tableWidget->setHorizontalHeaderLabels(TABLE_COLUMN_LABELS);
    ui->tableWidget->horizontalHeader()->setStretchLastSection(true);
    ui->tableWidget->verticalHeader()->hide();

    for(int i = 0; i<modelConnections->rowCount();++i){
        ui->tableWidget->insertRow(i);
        ui->tableWidget->setItem(i,0,new QTableWidgetItem(modelConnections->data(modelConnections->index(i,0,QModelIndex())).toString()));
        ui->tableWidget->setItem(i,1,new QTableWidgetItem(modelConnections->data(modelConnections->index(i,1,QModelIndex())).toString()));
        ui->tableWidget->setItem(i,2, new QTableWidgetItem("Проверка"));
    }

    ui->tableWidget->resizeColumnsToContents();

Вопрос как раз в реализации. Перечитав кучу доков и форумов я только окончательно запутался. А хотелось бы просто посмотреть кусок рабочего кода. :-)

0

Это если в одном потоке. В параллельных потоках надо создавать соединение, причем с разными именами, пример:

QSqlDatabase::addDatabase("QMYSQL", "db_thread1");
0

Это я в курсе, мне в потоке не надо пока подключатся к БД.

0

Так не даст подключится. Для потока создается отдельный пулл подключений к БД. я с этим уже сталкивался.

0

проверено на практике - делаем глобальный

global.h

extern QSqlDatabase db;

global.cpp

QSqlDatabase db;

в основном классе

 db=QSqlDatabase::addDatabase("QDB");
 db.setDatabaseName(db_name);
 db.setUserName(db_login);
 db.setHostName(db_host);
 db.setPassword(db_password)

и потом в любом месте в любом потоке через

QSqlQuery query(str,db);

имеем доступ к единственному экземпляру БД, и больше ничего создавать не нужно

0

примерно так (кусок реализации работы с системами Satel) soket.h

#ifndef SOCKET_H
#define SOCKET_H

#include <QTcpSocket>
#include <QByteArray>
#include <QInputDialog>

class socket : public QObject
{
    Q_OBJECT
public:
    socket(const QString name, const QString host, const int port, QWidget *parent = nullptr);
    QTcpSocket *psocket;
    QString name;//??
    QString host;
    int port;

    ~socket();

    void connect_to_tcp  ();
signals:
    //void printmsg(QString);
    void conect(socket* soc);
    void slotReadyRead (socket* soc, QTcpSocket* tsoc);
    void slotError (socket* soc, QTcpSocket* tsoc, QAbstractSocket::SocketError);
    //void slotConnected   (socket* soc);
};

soket.cpp

#include "socket.h"

socket::socket(const QString name, const QString host, const int port, QWidget *parent)
{
    psocket=new QTcpSocket(this);
    this->host=host;
    this->port=port;
    this->name=name;
    connect(psocket, &QTcpSocket::connected, [this]{emit conect(this);});
    connect(psocket, &QTcpSocket::readyRead, [this]{emit slotReadyRead(this,psocket);});
    connect(psocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
            [this](QAbstractSocket::SocketError socketError){emit slotError(this, psocket, socketError);});// SLOT(slotError(QAbstractSocket::SocketError)));
}

socket::~socket()
{

}

void socket::connect_to_tcp()
{
    psocket->connectToHost(host,port);
}

в основном рабочем классе делал так

 QSqlQuery query_m("SELECT name, ip_address, port FROM mod_satel");;
        while (query_m.next()) {
            QString name=query_m.value(0).toString();
            QString host=query_m.value(1).toString();
            int i = query_m.value(2).toInt();
            //qDebug() << "Adding new soket";
            socket* p_socket=new socket(name,host,i);
            connect(p_socket,&socket::conect, this,&satel::slotConnected_satel);
            connect(p_socket,&socket::slotReadyRead,this,&satel::slotReadyRead_satel);
            connect(p_socket,&socket::slotError,this,&satel::slotError_satel);
            m_socket.append(p_socket);
        }

идею взял вот с этой книжки "Lazar G., Penea R. - Mastering Qt 5 - 2016"

0

Спасибо, но меня больше интересует реализация потоков.

0

а что мешает потом сделать так? (при определенных условиях, отправляется в отдельный поток на обработку, количество совпадений по условию не предсказуемо)

 if(vector.contains(N))
{
    QtConcurrent::run(this, &satel::arm_disarm, buffer);
}
0

ну или попробывать такой вариант(ваш обьект в другом потоке останется жить пока не удалите)

 QSqlQuery query_m("SELECT name, ip_address, port FROM mod_satel");;
        while (query_m.next()) {
            QString name=query_m.value(0).toString();
            QString host=query_m.value(1).toString();
            int i = query_m.value(2).toInt();
            //qDebug() << "Adding new soket";
            socket* p_socket=new socket(name,host,i);
            connect(p_socket,&socket::conect, this,&satel::slotConnected_satel);
            connect(p_socket,&socket::slotReadyRead,this,&satel::slotReadyRead_satel);
            connect(p_socket,&socket::slotError,this,&satel::slotError_satel);
           QThread *thread=new QThread(this);
           p_socket->moveToThread(thread);
           thread->start();
        }
0
R

Добрий вечір, не рекомендував би вам використоувати для цих цілей, багато потоків, один потік це приблизно 67мб (принаймні було в моєму випадку) і того вам на 200 потоків потрібно не мало памяті, моя реалізація стосується роботи з QWebSocket короткий код нижче, все перевірено і працює, + не потрібно робити багато конекшинів з кожного потоку до бази, і не так важко реалізувати комунікацію

QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();

        QString id_socket = QString("%1%2").arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")).arg("blablabla");

        pSocket->setObjectName(id_socket);
        UserConnect* userThread = new UserConnect(pSocket);
        connect(pSocket, &QWebSocket::disconnected, this, &SSLWebSocketServer::socketDisconnected);
        connect(pSocket, &QWebSocket::disconnected, userThread, &UserConnect::deleteLater);

// цей параметр з іншого класу, але дляприкладу привів
    QMap<QString, QWebSocket *> clients;

    lients.insert(id_socket, pSocket);


далі можна робити комунікації по ObjectName

по типу
       QWebSocket *pSocket = clients.value(id_socket);

        if(pSocket)
        {
             pSocket->sendTextMessage(message);
        }
0
u
  • 18 апреля 2019 г. 2:20

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

0

я не знаю как у вас получилось 1поток=67мб (может у вас был не поток а процесс?). у меня есть проект, в нем постоянно активно 28 потоков, с таймерами и бесконечными циклами, и они регулярно стучат в БД,так вот там у меня с запущенным интерфейсом (QML) занято 105м,, без интерфейса все 42мб

0

Большое спасибо за наводящие ответы. :-) QTcpSocket мне нужен всего лишь для проверки доступна ли удаленная база данных. Если доступна, то тогда у же к ней будем обращаться с запросами.

0

отпишитесь потом по результатам, что получилось сколько занимает, и какая нагрузка в общем

0

Следующий этап это выполнение на каждой активной базе выполнять в потоке запрос

select t.TANK_ID, f.NAME from tanks t
left join FUELS f on f.FUEL_ID = t.FUEL_ID
where t.ISACTIVE = 'T'

Вот там и будем мерять. Потому что статистика выволнения не очень впечатляет :-)

Executing statement... Statement executed (elapsed time: 0.000s). 360 fetches, 19 marks, 7 reads, 16 writes. 0 inserts, 0 updates, 0 deletes, 33 index, 14 seq. Delta memory: 200 bytes. Total execution time: 5.026s Script execution finished.

Кстати вопрос на эту тему. QSqlQuery позволяет какимно образом получать такую информаци?

0

Реаизовал с использованием QtConcurent, дабы получить сигнал что все потоки по опросу порта завершились.

    checkOnline = new QFutureWatcher<bool>(this);
    connect(checkOnline,&QFutureWatcher<QTcpSocket>::started, this, &ShowPage::slotStartExecute);
    connect(checkOnline,&QFutureWatcher<QTcpSocket>::resultReadyAt,this,&ShowPage::slotStopExecute);
    connect(checkOnline,&QFutureWatcher<QTcpSocket>::finished,this,&ShowPage::slotFinished);

    std::function<bool(QString)> getOnline = [] (const QString ipAZS){
        QTcpSocket tcpSocket;
        tcpSocket.connectToHost(ipAZS,3050);
        return tcpSocket.waitForConnected(30000);
    };

    checkOnline->setFuture(QtConcurrent::mapped(m_listIP,getOnline));
}


void ShowPage::slotStartExecute()
{
   qInfo(logInfo()) << Q_FUNC_INFO << QDateTime::currentDateTime().toString("dd-MM-yyyy hh:mm:ss.zzz") <<  "Thread started";
}

void ShowPage::slotStopExecute(int term)
{
    if(checkOnline->resultAt(term)) {
        ui->tableWidget->item(term, 2)->setText("ON LINE");
        ui->tableWidget->item(term,2)->setTextColor("Green");
        ui->tableWidget->item(term, 2)->setIcon(QIcon(":/Icons/connect.png"));
    } else {
        ui->tableWidget->item(term, 2)->setText("OFF LINE");
        ui->tableWidget->item(term, 2)->setTextColor("Red");
        ui->tableWidget->item(term, 2)->setIcon(QIcon(":/Icons/disconnect.png"));
    }
}

void ShowPage::slotGetAzsStatus(bool res)
{
    isOnline = res;
}

void ShowPage::slotFinished()
{
    qInfo(logInfo()) << "QtConcurent finished";
}
0

отпишитесь потом по результатам, что получилось сколько занимает, и какая нагрузка в общем

А как мерять :-)

0

просто скажите что по загрузке процессора и оперативы, когда происходит опрос

0

Можно просмотреть результаты тут https://drive.google.com/file/d/1tFmrljPrxjqkb6OZSvCmF5uGtuHvlKPq/view?usp=sharing

0
R

мені важко це зараз навіть перевірити, тому що знайшов коміт, це ще було в 2016 році, і цей код не буде працювати коректно зараз, єдине скажу що це були QThread

0

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
AA
17 апреля 2019 г. 19:40
Anton Ablin

Qt - Тест 001. Сигналы и слоты

  • Результат:73баллов,
  • Очки рейтинга1
E
17 апреля 2019 г. 18:16
Evgeny

Qt - Тест 001. Сигналы и слоты

  • Результат:100баллов,
  • Очки рейтинга10
E
17 апреля 2019 г. 18:14
Evgeny

Qt - Тест 001. Сигналы и слоты

  • Результат:78баллов,
  • Очки рейтинга2
Последние комментарии
U
18 апреля 2019 г. 15:37
Unreal_man

А как иконку в хедер задать?
u
18 апреля 2019 г. 2:15
uaa

доброго времени,большое спасибо за пример для начинающего)при адаптации к своему проекту столкнулся с таким ньансом:в vepolyline.h в 47 строке нужна инициализация по умолчанию: int m_pointF...
E
11 апреля 2019 г. 12:49
Evgeny

Спасибо за ответ) У меня компоновщик на нее ругался просто. Оказалось, просто забыл Q_OBJECT в начале класса указать.
11 апреля 2019 г. 12:29
Евгений Легоцкой

Добрый день. Вы имели ввиду реализацию? Для сигналов в Qt реализация не пишется, это всё генерируется в moc файлах под капотом Qt.
E
11 апреля 2019 г. 12:15
Evgeny

Здравствуйте. А где описание функции signal1()?
Сейчас обсуждают на форуме
R
19 апреля 2019 г. 9:55
RED_Spider

мені важко це зараз навіть перевірити, тому що знайшов коміт, це ще було в 2016 році, і цей код не буде працювати коректно зараз, єдине скажу що це були QThread
i
17 апреля 2019 г. 15:03
ilya.guzikov

BlinCT, на стороне ++ это делать необходимо так как в qml при использовании функции append происходит перерисовка всех точек лини(как я понимаю) и из-за этого при использовании больших массиво...
10 апреля 2019 г. 11:20
Алексей Внуков

может тоже кому надо будет - QML не принимает QVector<QVector<int>> , при попытке вывести полученый вектор QML показывает что это QVariant(QVector<QVector<int> ...
SN
10 апреля 2019 г. 9:36
Stanislav Nykytiuk

Как реализовать такое меню, что бы нажмаешь меню подменю и выбор позиции? Данные меню и подменю в базе SQL.
Присоединяйтесь к нам в социальных сетях

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