" title="Написать письмо">Написать письмо
Донаты на карту ВТБ:
5368 2902 0040 0838

Статистика

Пользователи : 1
Статьи : 2069
Просмотры материалов : 7577750
 
Многопоточность: получилось (12.07.2024). Печать E-mail
2024 - Июль
12.07.2024 17:20
Save & Share
С перерывами в несколько лет, в разных средах разработки, - пытался сделать корректную многопоточность в приложении. Однако в средах разработки до 2015 года с этим был какой-то треш (раз, два - даже извраты делать пришлось: раз, два). И единственное, что удалось сделать: заставить работать второе ядро процессора в Borland C++ Builder v.6.0 в Windows XP. Ни примеры в интернете не помогали (несовместимы, ошибочны, не работают), ни форумы (нет решивших людей эту задачку, в т.ч. с корректными исходниками).

Между тем, хочу напрогать приблуду - лютую и конфиденциальную. И, с учётом того, что дома теперь частоты ниже, а потоков 24, - пришлось сделать ещё попытку. Удалось реализовать - только на Qt v.5.15.2 в среде Astra Linux SE v.1.7.4.0 (7).



Сначала всё было то же самое: ни один из примеров к более новым версиям Qt не работал. Например, отсутствуют QThread::create или bind; или connect не компилируется, или класс не создаётся, или метод run в QtConcurrentRun на фиг посылает. В итоге, примеры были выкинуты в мусорку - и стал делать по логике и с отключенным мозгом (в надежде, что в алогичной и враждебной среде Qt хотя бы с этим механизмом багов нет).

Ага, щазз.

Сначала был создан простейший класс, именно в mainwindow.h: с некоторым набором функций, раскидываемых по разным потокам и работающих по-разному - с целью более детального тестирования.

class Thread_Functions : public QObject {
    Q_OBJECT
public slots:
    void vPrint_Lesha_30sec(void);
    void vPrint_Nubas_60sec(void);
    void vBurn_Core_30sec(void);
    void vBurn_Core_60sec(void);
};

Уже надрочившись с примерами - сформировался список необходимых инклудов в CPP-файле.

#include "qthread.h"
#include "qdebug.h"
#include "qdatetime.h"


Функции нагрузки ядра были созданы для понимания, как работают потоки через загрузку процессора в диспетчере устройств.

void Thread_Functions::vBurn_Core_30sec(void)
{
    quint64 qui64Begin = QDateTime::currentMSecsSinceEpoch();

    while (QDateTime::currentMSecsSinceEpoch()-qui64Begin < 30000) {}
}


Это дало результаты:
- и объект класса с функциями, и объект потока - должны создаваться локально в месте старта потока. Глобальный объект потока портится после отработки, глобальный объект функций приводит к работе только одного потока за раз;
- moveToThread по-прежнему недостаточно, чтобы засунуть объект с функциями в поток так, чтобы он работал;
- удалось сформировать удачный connect, в интернете не описываемый. Простой до безобразия - но отсутствующий в примерах, и обязательно со словами "SIGNAL" и "SLOT" в строке - безо всяких амперсандов, скобок, точек, стрелок и прочей фигни;
- диспетчер задач показывает, что поток не убивается после выполнения, несмотря на уничтожение самого объекта. Возможно, баг ОС, - но на работу не влияет;
- чёткая цифра 8% процессора на ядро (опять баг ОС: 8.3(3) должно быть) позволяет чётко понимать, сколько потоков работает - перепроверка багов цифры о количестве потоков;
- 12 кнопок для 12 потоков - успешно жгли процессор на 100% загрузки. Общее количество потоков при первом запуске 13, при втором - 25. Если нажимать на одну и ту же кнопку несколько раз - оказалось равнозначным нажатию на несколько разных.

void MainWindow::on_pushButton_Nubas_clicked()
{
    Thread_Functions *oThread_Functions = new Thread_Functions();
    QThread *oThread = new QThread();

    oThread_Functions->moveToThread(oThread);
    connect(oThread, SIGNAL(started()), oThread_Functions, SLOT(vPrint_Nubas_60sec()));
    //connect(oThread, SIGNAL(started()), oThread_Functions, SLOT(vBurn_Core_60sec()));
    oThread->start();
}


Вывод сообщений в дебаг и стринглист показали:
- не требуется использовать функции типа lock для разделения данных разных потоков друг от друга;
- поток отрабатывает строго по времени - именно большой буфер продолжает выводиться в Вывод Приложения, даже после выхода из программы;
- баг Qt: ни clear, ни delete, ни NULL - не удаляют QStringList до конца - в итоге, при многократном использовании, 32ГБ RAM быстро переполнились.

void Thread_Functions::vPrint_Lesha_30sec(void)
{
    quint64 qui64Begin = QDateTime::currentMSecsSinceEpoch();
    QStringList *qslTexts = new QStringList;

    //while (QDateTime::currentMSecsSinceEpoch()-qui64Begin < 30000) qDebug() << "Lesha - ";
    while (QDateTime::currentMSecsSinceEpoch()-qui64Begin<30000 && qslTexts->count()<21460000) qslTexts->append("Lesha - ");

    for (int iCurrent_Position=0; iCurrent_Position<qslTexts->count(); iCurrent_Position++)
    {
        if (!qslTexts->at(iCurrent_Position).contains("Lesha - ")) qDebug() << "Ne Lesha!";
    }

    qslTexts->clear();

    delete qslTexts; qslTexts = NULL;

    int iStopper = 0; //Проверка времени вывода надписей: глючит не функция, а Qt. Огромный объём данных продолжает писаться в Вывод Приложения - даже если программа уже закрыта.
}

Так как в слоты нельзя передавать параметры - пока неясно, как сделать взаимодействие потока с UI.

В полезных исходниках целиком проект выложен.

(добавлено 13.07.2024) Да, похоже, 2015 год - граница корректности работы средств разработки с многопоточностью (в плане понятности и удобства использования разработчиком). В Visual Studio 2015 года показали реально работающую реализацию - ещё удобнее, чем в Qt: всего несколько строк, без всяких слотов, классов и прочей хрени - но с принудительным залочиванием каждого потока.

(добавлено 04.08.2024) С Borland C++ Builder - всё получилось, попроще и пологичнее.
Обновлено ( 04.08.2024 04:37 )
 
 

Последние новости


©2008-2024. All Rights Reserved. Разработчик - " title="Сергей Белов">Сергей Белов. Материалы сайта предоставляются по принципу "как есть". Автор не несет никакой ответственности и не гарантирует отсутствие неправильных сведений и ошибок. Вся ответственность за использование материалов лежит полностью на читателях. Размещение материалов данного сайта на иных сайтах запрещено без указания активной ссылки на данный сайт-первоисточник (ГК РФ: ст.1259 п.1 + ст.1274 п.1-3).

Много статей не имеет срока устаревания. Есть смысл смотреть и 2011, и даже 2008 год. Политика сайта: написать статью, а потом обновлять ее много лет.
Рекламодателям! Перестаньте спамить мне на почту с предложениями о размещении рекламы на этом сайте. Я никогда спамером/рекламщиком не был и не буду!
Top.Mail.Ru