I have a GUI with a progress bar, and when I click RUN on my GUI, it progress a lot of calculations. The progress bar is updated to show progress. This works perfectly fine when I had the main thread do all of the calculations. This was very slow so I have updated to have multiple threads do the calculations, each updating the progress bar accordingly as they go. Here is my implementation (simplified):
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//do some stuff
MainWindow w(F1, F2);
w.show();
return a.exec();
}
mainwindow.cpp
MainWindow::MainWindow(int F1, int F2, QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//do some stuff
//set up GUI
}
void MainWindow::MyMainFunction(/*some parameters here*/)
{
//do some stuff
int progress;
//do more stuff and update progress bar
ui->progressBar->setValue(progress);
QApplication::processEvents();
//do more stuff and update progress bar
ui->progressBar->setValue(progress);
QApplication::processEvents();
std::vector<double> myVector; //create myVector and add data
//start a LOT of calculations - using multiple threads
int numThreads = QThread::idealThreadCount() * 0.75; //set the number of threads
int chunkSize = myVector.size() / numThreads; //set the chunk size for each thread to process
QVector<QThread *> threads(numThreads); //set up the threads
for (int threadNo = 0; threadNo < numThreads; threadNo = threadNo + 1) //loop through each thread
{
int startIndex = threadNo * chunkSize; //get the start index for the thread
int endIndex = (threadNo + 1) * (chunkSize - 1)); //get the end index for the thread
if (threadNo == numThreads - 1) //deal with the last chunk
{
endIndex = myVector.size() - 1; //deal with the last chunk
}
threads[threadNo] = new QThread; //initiate thread
//set up lambda function
QObject::connect(threads[threadNo], &QThread::started, [=,&F1, &F2]
{
qDebug() << "Processing calculations in thread " << QThread::currentThreadId() << ".";
for (int i = 0; i < 60000; i = i + 1) //set up outer loop
{
int progress = //quick calc to check the progress
if (progress > ui->progressBar->value() + 1) //only update the progress if it has increased by at least 1%
{
//APPLY MUTEX LOCK HERE //make sure progress bar isnt updated by more than one thread at once
ui->progressBar->setValue(progress); //Update progress bar
QApplication::processEvents(); //process GUI events
//END MUTEX LOCK HERE //make sure progress bar isnt updated by more than one thread at once
}
for (int j = 0; j < 1000; j = j + 1) //set up inner loop
{
//DO LOADS OF CALCULATIONS HERE //do calculations
}
}
return; //thread finished
});
}
// Start the work for each thread
for (int i = 0; i < numThreads; i = i + 1)
{
threads[i]->start();
qDebug() << "Thread " << i << " started.";
}
// wait for each thread to finish
QMutexLocker locker(&waitConditionMutex);
for (int i = 0; i < numThreads; i = i + 1)
{
waitCondition.wait(&waitConditionMutex);
qDebug() << "Thread " << i << " finished";
}
locker.unlock();
// now delete the threads
for (int i = 0; i < numThreads; i = i + 1)
{
threads[i]->exit();
threads[i]->wait();
delete threads[i];
}
qDebug() << "All threads finished.";
}
The problem now is that when the calculations start, the progress bar updates for a couple of seconds and then the GUI freezes, but the calculations carry on in the background. The threads are doing the calculations correctly, obviously its a lot faster now, and when the calculations are done, the GUI unfreezes. I dont know what I am doing wrong to make the GUI freeze.
I have tried to call a function to update the progress bar, rather than directly using ui->progressBar->setValue. I have also tried to add in a 0.75 factor to the numThreads, but that also didnt work.
I appreciate this is a lot of information, but any guidance would be useful. I'm hoping there is an easy solution, or I have messed up somewhere.
Thank you!