I'm making an emulator and I need to run the loop that executes instructions in another thread (preferably with QtConcurrent). I am currently doing it like this
#include <QtConcurrent/QtConcurrentRun>
#include <QThread>
QFutureWatcher<void> futureWatcher;
bool running = false;
void MainWindow::startExecution() {
running = true;
futureWatcher.setFuture(QtConcurrent::run([this]() {
while(running){
qDebug() << "Physical Thread ID: " << QThread::currentThreadId();
QThread::msleep(100);
//execute instructions
}
}));
}
void MainWindow::stopExecution()
{
running = false;
futureWatcher.waitForFinished();
}
The issue is every time that futureWatcher is run, it starts running in another thread. And after 8 runs (or how many threads my CPU has) the futureWatcher won't run anymore. I proved this by doing this:
qDebug() << "Physical Thread ID: " << QThread::currentThreadId();
This is called as soon as the futureWatcher starts.
Snippet of the output:
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x8c4
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x1414
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x20d0
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x2768
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x2768
called from Physical Thread ID: 0x2768
Physical Thread ID: 0x2768
As soon as the threads are the same, it no longer behaves correctly and the loop doesn't run when setFuture is called, but it is actually run when futureWatcher.waitForFinished(); is called in stopExecution().
I only need 2 threads. One is the main thread and the other for the execution. Is there a way to always run the future watcher in the same second thread? What other solutions can I use?
The problem you are encountering is that
QtConcurrent::runby default uses the globalQThreadPool, which has a limited number of threads (usually as many as the number of CPU cores). Once all threads are in use, additional calls toQtConcurrent::runwill queue the tasks until a thread becomes available.In your case, because
runningis not turnedfalsebefore callingwaitForFinished(), the threads may not be properly released back to the pool. This is why after several runs, you no longer have any threads available to run new tasks.If you want to ensure that you always have a thread available for your emulator's execution loop, you could create your own
QThreadPoolwith a single thread and use that for your concurrent tasks.Here's a rough example of how you could modify your code:
With this setup, you're controlling the thread pool directly and ensuring that only one thread will be used for your task, separate from the global thread pool. This should prevent the exhaustion of threads in the global pool.
Remember to handle thread safety when accessing and modifying shared resources between the main thread and the execution thread. If
runningis shared, it should at least be an atomic variable to prevent race conditions.Finally, make sure to properly clean up the thread pool when your application is closing to prevent any threads from continuing to run in the background.
Resource: ChatGPT-4