Потоки в 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 шт):
А зачем вам векторы потоков и объектов? Полностью ваш код конечно не видел, но я бы сделал так: Правильнее было бы так
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(); // запускаем поток
}
ЗЫЖ А касаемо вашей реализации - проблема в том что у вас вызывается метод объекта. Потоки даже не запускаются
Итог:
Конструктор:
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();
}