Потоки в QVector Qt

Пишу многопоточное приложение на Qt 5.13.1. Так как планируется кроссплатформенность и переносимость, пытаюсь создать количество потоков в зависимости от количества потоков процессора. При обычном создании потоков никаких проблем нет:

QThread thread1, thread2;

Counter *counter1 = new Counter;
counter1->moveToThread(&thread1);
Counter *counter2 = new Counter;
counter2->moveToThread(&thread2);

connect(this, &CodAn::signalToCount1, counter1, &Counter::count);
connect(this, &CodAn::signalToCount2, counter2, &Counter::count);

thread1.start();
thread2.start();

for (int i = 0; i < pathsVector.size(); i++)
{
    switch (i % 4)
    {
    case 0:
        emit signalToCount1(pathsVector[i]);
        break;
    case 1:
        emit signalToCount2(pathsVector[i]);
        break;
    }
}

Каждая задача запускается в отдельном потоке. Однако, при попытке динамически создать потоки, задача выполняется в GUI-потоке, приложение виснет, пока не досчитает:

QVector<QThread*> threads;
QVector<Counter*> counters;

int threadCount = QThread::idealThreadCount();

for (int i = 0; i < threadCount; i++)
{
    counters.append(new Counter);
    threads.append(new QThread);
    counters.at(i)->moveToThread(threads.at(i));
}

for (int i = 0; i < threads.size(); i++)
    threads.at(i)->start();

for (int i = 0; i < pathsVector.size(); i++)
{
    counters.at(i % counters.size())->Counter::count(pathsVector[i]);
}

pathsVector - обычный QVector из QString. В чём моя проблема? Грешу на последнюю строку, но не могу придумать, как создать сигнал-слотовое соединение.


Ответы (2 шт):

Автор решения: Sergey Tatarincev

А зачем вам векторы потоков и объектов? Полностью ваш код конечно не видел, но я бы сделал так: Правильнее было бы так

 int threadCount = QThread::idealThreadCount();
 for (int i = 0; i < threadCount; i++){
    QThread* thread = new QThread(); // Создаем экземпляр потока
    Counter* counter = new Counter(); // Создаем экземпляр объекта-счетчика
    counter->Init(pathsVector[i]); // Самое простое - инициализировать новый экземпляр данными до запуска потока. Counter::Init(QString) - прописываете в своем объекте
    counter->moveToThread(thread); 
    connect(thread, SIGNAL(started()), counter, SLOT(Processing())); // При запуске потока должна начать выполняться Counter::Processing() - прописываете в своем объекте
    connect(thread, SIGNAL(finished()), counter, SIGNAL(finished())); // При завершении потока необходимо остановить и вычисление в Couter
    connect(counter, SIGNAL(finished()), counter, SLOT(deleteLater())); // При завершении работы Counter, необходимо удалить экземпляр объекта
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); // При завершении работы потока, экземпляр потока стоит удалить
    thread->start(); // запускаем поток
}

ЗЫЖ А касаемо вашей реализации - проблема в том что у вас вызывается метод объекта. Потоки даже не запускаются

→ Ссылка
Автор решения: Georgesma

Итог:

Конструктор:

int threadCount = QThread::idealThreadCount();
if (threadCount == 0 || threadCount == -1) threadCount = 1;

for (int i = 0; i < threadCount; i++)
{
    counters.append(new Counter());
    threads.append(new QThread());
    pathsVectors.append(new QVector <QString>);

    connect(threads.at(i), SIGNAL(started()), counters.at(i), SLOT(start()));
    connect(threads.at(i), SIGNAL(finished()), counters.at(i), SIGNAL(finished()));
    connect(counters.at(i), SIGNAL(finished()), threads.at(i), SLOT(quit()));
    connect(counters.at(i), &Counter::countFinished, this, &CodAn::handleFinish);
}

Деструктор:

for (int i = 0; i < threads.count(); i++)
{
    threads.at(i)->quit();
    threads.at(i)->wait();
}

Кнопка, по которой происходит вычисление:

for (int i = 0; i < pathsVector.size(); i++)
{
    pathsVectors[i % counters.size()]->append(pathsVector.at(i));
}

for (int i = 0; i < pathsVectors.size(); i++)
{
    counters.at(i)->init(*pathsVectors.at(i));
    counters.at(i)->moveToThread(threads.at(i));
    threads.at(i)->start();
    pathsVectors.at(i)->clear();
}
→ Ссылка