diff --git a/QMain.cpp b/QMain.cpp new file mode 100644 index 0000000..7aa375a --- /dev/null +++ b/QMain.cpp @@ -0,0 +1,99 @@ +#include "QMain.h" + +QMain::QMain(QObject *parent) : QObject(parent) +{ + qDebug() << QString("[ QMain ] QMain()"); + + qRegisterMetaType>("QVector"); + + w1 = new QWorker("Worker1"); + w2 = new QWorker("Worker2"); + w3 = new QWorker("Worker3"); + + currentTry = 0; + + connect(w1, SIGNAL(workerFinished(QString, QVector, int)), this, SLOT(workerSendResult(QString, QVector, int)), Qt::DirectConnection); + connect(w2, SIGNAL(workerFinished(QString, QVector, int)), this, SLOT(workerSendResult(QString, QVector, int)), Qt::DirectConnection); + connect(w3, SIGNAL(workerFinished(QString, QVector, int)), this, SLOT(workerSendResult(QString, QVector, int)), Qt::DirectConnection); + + connect(this, SIGNAL(restart()), this, SLOT(beginSort()), Qt::QueuedConnection); + + connect(this, SIGNAL(startWorker(QVector)), w1, SLOT(mergeSort(QVector))); + connect(this, SIGNAL(startWorker(QVector)), w2, SLOT(bubbleSort(QVector))); + connect(this, SIGNAL(startWorker(QVector)), w3, SLOT(quickSort(QVector))); + + stopPointers << &w1->stop << &w2->stop << &w3->stop; + + w1->moveToThread(&t1); t1.start(); + w2->moveToThread(&t2); t2.start(); + w3->moveToThread(&t3); t3.start(); +} + +QMain::~QMain() +{ + qDebug() << QString("[ QMain ] ~QMain()"); + t1.quit(); t1.wait(); delete w1; t1.deleteLater(); + t2.quit(); t1.wait(); delete w2; t2.deleteLater(); + t3.quit(); t1.wait(); delete w3; t3.deleteLater(); +} + +QVector QMain::generateRandomVector() +{ + QVector data; + data.reserve(VECTOR_SIZE); + + QRandomGenerator rnd; + + qDebug() << QString("[ QMain ] Generating random vector..."); + for (int i = 0; i < VECTOR_SIZE; ++i) + { + data.append(rnd.bounded(INT_MIN, INT_MAX)); + } + qDebug() << QString("[ QMain ] Ready!"); + + return data; +} + +void QMain::beginSort() +{ + activeThreads = THREADS; + stop = false; + currentTry++; + + qDebug() << QString("[ QMain ] ------------"); + qDebug() << QString("[ QMain ] Try %1 of %2").arg(currentTry).arg(TRY_COUNT); + + emit startWorker(generateRandomVector()); +} + +void QMain::workerSendResult(QString name, QVector data, int msecs) +{ + mutex.lock(); + if (stop) + { + qDebug() << QString("[ %1 ] sort stopped.").arg(name); + } + else + { + stop = true; + for (volatile bool *ptr : stopPointers) *ptr = true; + qDebug() << QString("[ %1 ] Finished with %2 msecs!").arg(name).arg(msecs); + qDebug() << QString("[ %1 ] Elements: %2").arg(name).arg(data.size()); + // Do something with result + //for (int a : data) + // qDebug() << a; + } + workerStopped(); + mutex.unlock(); +} + +void QMain::workerStopped() +{ + if (!--activeThreads) + { + if (currentTry == TRY_COUNT) + emit closeProgram(); + else + emit restart(); // Прямой вызов нельзя - иначе управление перейдет к "финишировавшему потоку" + } +} diff --git a/QMain.h b/QMain.h new file mode 100644 index 0000000..f01ba2d --- /dev/null +++ b/QMain.h @@ -0,0 +1,49 @@ +#ifndef QMAIN_H +#define QMAIN_H + +#include +#include +#include +#include +#include + +#include + +#include "QWorker.h" + +#define TRY_COUNT 10 // Количество повторов +#define VECTOR_SIZE 10000000 // Размер массива + +#define THREADS 3 // Не менять! + +class QMain : public QObject +{ + Q_OBJECT +public: + explicit QMain(QObject *parent = nullptr); + ~QMain(); + +signals: + void closeProgram(); + void startWorker(QVector data); + void restart(); + +public slots: + void beginSort(); + void workerSendResult(QString name, QVector data, int msecs); + void workerStopped(); + +private: + QThread t1, t2, t3; + QWorker *w1, *w2, *w3; + QMutex mutex; + QVector stopPointers; + bool stop; + int activeThreads; + int currentTry; + +private: + QVector generateRandomVector(); +}; + +#endif // QMAIN_H diff --git a/QThreadPerversions.pro b/QThreadPerversions.pro new file mode 100644 index 0000000..1d67921 --- /dev/null +++ b/QThreadPerversions.pro @@ -0,0 +1,23 @@ +QT -= gui + +CONFIG += c++11 console +CONFIG -= app_bundle + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += main.cpp \ + QMain.cpp \ + QWorker.cpp + +HEADERS += \ + QMain.h \ + QWorker.h diff --git a/QWorker.cpp b/QWorker.cpp new file mode 100644 index 0000000..b4245d2 --- /dev/null +++ b/QWorker.cpp @@ -0,0 +1,127 @@ +#include "QWorker.h" + +QWorker::QWorker(QString _name, QObject *parent) : QObject(parent) +{ + name = _name; + qDebug() << QString("[ %1 ] QWorker()").arg(name); +} + +QWorker::~QWorker() +{ + qDebug() << QString("[ %1 ] ~QWorker()").arg(name); +} + +void QWorker::mergeSort(QVector _data) +{ + QTime timeBegin = QTime::currentTime(); + qDebug() << QString("[ %1 ] sort started.").arg(name); + + stop = false; + data = mergeSortBody(_data); + + emit workerFinished(name, data, timeBegin.msecsTo(QTime::currentTime())); +} + +QVector QWorker::mergeSortBody(QVector data) +{ + if (data.size() <= 1 || stop) + return data; + + QVector left = mergeSortBody(data.mid(0, data.size() / 2)); + QVector right = mergeSortBody(data.mid(left.size(), data.size() - left.size())); + + return mergeBody(left, right); +} + +QVector QWorker::mergeBody(QVector left, QVector right) +{ + QVector result; + result.reserve(left.size() + right.size()); + + int leftFirstIndex = 0; + int rightFirstIndex = 0; + + while (leftFirstIndex < left.size() && rightFirstIndex < right.size() && !stop) + if (left.at(leftFirstIndex) <= right.at(rightFirstIndex)) + result.append(left.at(leftFirstIndex++)); + else + result.append(right.at(rightFirstIndex++)); + + if (left.size() - leftFirstIndex > 0) + result.append(left.mid(leftFirstIndex)); + if (right.size() - rightFirstIndex > 0) + result.append(right.mid(rightFirstIndex)); + + return result; +} +void QWorker::bubbleSort(QVector _data) +{ + QTime timeBegin = QTime::currentTime(); + qDebug() << QString("[ %1 ] sort started.").arg(name); + + stop = false; + data = _data; + + bool swapped; + do + { + swapped = false; + for (int i = 1; i < data.size() && !stop; ++i) + if (data.at(i-1) > data.at(i)) + { + int tmp = data.at(i); + data[i] = data.at(i-1); + data[i-1] = tmp; + swapped = true; + } + } + while (swapped != false && !stop); + + emit workerFinished(name, data, timeBegin.msecsTo(QTime::currentTime())); +} + +void QWorker::quickSort(QVector _data) +{ + QTime timeBegin = QTime::currentTime(); + qDebug() << QString("[ %1 ] sort started.").arg(name); + + stop = false; + data = _data; + + quickSortBody(data); + + emit workerFinished(name, data, timeBegin.msecsTo(QTime::currentTime())); +} + +void QWorker::quickSortBody(QVector &data, int start, int end) +{ + if (end == -1) end = data.size() - 1; + + if (start >= end || stop) return; + + int base = quickSortPart(data, start, end); + + quickSortBody(data, start, base - 1); + quickSortBody(data, base + 1, end); +} + +int QWorker::quickSortPart(QVector &data, int start, int end) +{ + int temp; + int marker = start; + + for (int i = start; i <= end && !stop; ++i) + if (data.at(i) < data.at(end)) + { + temp = data.at(marker); + data[marker] = data.at(i); + data[i] = temp; + marker++; + } + + temp = data.at(marker); + data[marker] = data.at(end); + data[end] = temp; + + return marker; +} diff --git a/QWorker.h b/QWorker.h new file mode 100644 index 0000000..d4c531d --- /dev/null +++ b/QWorker.h @@ -0,0 +1,39 @@ +#ifndef QWORKER_H +#define QWORKER_H + +#include +#include +#include + +class QWorker : public QObject +{ + Q_OBJECT +public: + explicit QWorker(QString _name, QObject *parent = nullptr); + ~QWorker(); + + volatile bool stop; + +public slots: + void mergeSort(QVector _data); + void bubbleSort(QVector _data); + void quickSort(QVector _data); + +signals: + void workerFinished(QString name, QVector data, int msecs); + +private: + QVector mergeSortBody(QVector data); + QVector mergeBody(QVector left, QVector right); + + void quickSortBody(QVector &data, int start = 0, int end = -1); + int quickSortPart(QVector &data, int start, int end); + +private: + QString name; + QVector data; + +private: // sort sub +}; + +#endif // QWORKER_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..744ac25 --- /dev/null +++ b/main.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include "QMain.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + QMain shell; + + QObject::connect(&shell, SIGNAL(closeProgram()), &a, SLOT(quit())); + QTimer::singleShot(0,&shell,SLOT(beginSort())); + + return a.exec(); +}