QThread threadpool - c++

I am trying to write thread poll with QThread.
class ThreadPool: public QObject
{
Q_OBJECT
public:
ThreadPool(int maxThreads);
void addTask(MyTask *task);
private:
int maxThreads;
QMutex mutex;
QVector<QPair<bool, QThread>> threads;
QThread *getFreeThread();
public slots:
void freeThread();
};
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
task->moveToThread(thread);
connect(thread, SIGNAL(started()), task, SLOT(doWork()));
connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), task, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(freeThread()));
thread->start();
}
I am creating a limited number of threads in which I want to perform tasks.
However, I do not understand how to get the number of the freed thread.
I know about QThreadPool and Qtconcurrent, but I dont want to use it.
Perhaps, it is worth noting at each thread in QPair's vector is it free or not.

you do not really need a QVector<QPair<bool, QThread>> to keep track of all the threads in your Pool, instead use a QList< QThread* > which holds only the pointers to the free threads.
private:
QList<QThread*> freeThreads; // only free threads
QList<QThread*> allThreads; // just to count the number of all threads
In the slot freeThread() use the sender() method from QObject to get the pointer of the signal sender, which in this case will be the QThread, that has become free
void ThreadPool::freeThread()
{
// get the pointer to the thread that sent the signal:
QObject* threadFreed = QObject::sender();
if( ! freeThreads.contains( threadFreed ) )
{
// save the thread pointer in list
freeThreads << threadFreed;
}
}
Finally getFreeThread() can look like this:
QThread* getFreeThread()
{
if( ! freeThreads.isEmpty() )
{
// take the first free thread
return freeThreads.takeFirst();
}
else
{
if(allThreads.size() < maxThreads )
{
// create a new thread
QThread* thread = new QThread(this);
allThreads << thread;
return thread;
}
else
{
// Maximum number of threads exceeded
// and no free thread is available
return NULL;
}
}
}
Also you should handle the case when a NULL pointer is returned in addTask:
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
if( ! thread )
{
// do something else
return;
}
// proceed with thread execution ...
}

Related

How to share data between threads using QThread

I'm trying to learn how to share data between threads using QThread.
In my code below
when I try to print the value of worker_str sometimes i get an exception in the file qdebug.cpp:
Exception thrown: read access violation.
**p** was 0x111011101110111.
and sometimes it prints worker_str as "".
What I'm doing wrong? also, I should call thread->quit(); whenever I don't need that thread running anymore?
#include "worker.h"
App::App(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
QThread* thread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(thread);
QString str = "hello world";
connect(thread, &QThread::started, worker, [worker, str]
{
worker->test(str);
});
connect(worker, &Worker::finished, thread, [worker, thread]
{
qDebug() << "worker_str: " << worker->worker_str;
thread->quit();
});
connect( worker, &Worker::finished, worker, &Worker::deleteLater);
connect( thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
//worker.h
class Worker : public QObject {
Q_OBJECT
public:
Worker() {};
~Worker() {};
QString worker_str;
public slots:
void test(QString str)
{
worker_str = str;
qDebug() << "WORKER: str: " << str;
emit finished();
};
signals:
void finished();
};
About the code: I think the object "QString str" is no longer in memory after leaving the constructor scope. Make the variable a member of the class App.
Generally look into the topics mutex, lock guard or qt signal/slots. What you use in the end is up to your requirements.

How to stop threads in Qt

What is the corrent way to stop threads in Qt?
Suppose that I have a worker (LicenseChecker class) and I want to do some actions every n seconds in the process member function. I need to do it indefinitely, until someone abort my loop.
_worker = new LicenseChecker;
_thread = new QThread;
_worker->moveToThread(_thread);
connect(_thread, SIGNAL(started()), _worker, SLOT(process()));
connect(_worker, SIGNAL(finished()), _thread, SLOT(quit()));
connect(_worker, SIGNAL(finished()), _worker, SLOT(deleteLater()));
connect(_thread, SIGNAL(finished()), _thread, SLOT(deleteLater()));
connect(_worker, SIGNAL(newLicensesActivated(QVector<LicenseInfo>)),
this, SLOT(newLicensesActivated(QVector<LicenseInfo>)));
_thread->start();
What can I do to abort it?
The first idea that I came up with was to define the sleep function as the following:
bool LicenseChecker::sleep(int seconds)
{
QTime end_time = QTime::currentTime().addSecs(seconds);
while (QTime::currentTime() < end_time)
{
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
QMutexLocker lock(&_abort_sync);
if (_abort)
{
return false;
}
}
return true;
}
and to check the return code of this function in my infinite loop:
while (true)
{
if (!sleep(5))
{
emit finished();
return;
}
// ...
}
And then on MainWindow's close event I need to do the following:
_worker->stop();
_thread->wait();
where stop member function just sets _abort data member to true, but the application hangs on these calls.
What is the right way to accomplish such task?
Seems that you call stop() from another thread (the main thread) but the worker instance is located in the worker thread. You can overcome this problem by carefully writing something like this to invoke a method from another thread:
void Worker::stop()
{
// make thread safe
if(QThread::currentThread() != this->thread())
{
this->metaObject()->invokeMethod(this, "stop", Qt::QueuedConnection);
return;
}
REAL CODE HERE ...
}
Besides that, i would rather use a timer to fire every n seconds to do the licence check. Something like that (example of an database connection checker):
dbCheckerThread = new QThread(this);
dbCheckerTimer = new QTimer();
dbCheckerTimer->setInterval(CHECKDBCONNECTIONINTERVALL);
dbCheckerTimer->moveToThread(dbCheckerThread);
dbChecker->moveToThread(dbCheckerThread);
connect(dbCheckerTimer, &QTimer::timeout, dbChecker, &DbConnectionChecker::checkConnection);
connect(dbCheckerThread, &QThread::started, dbCheckerTimer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
dbCheckerThread->start();

Pause / resume Qthread from Worker

In the Worker Class I have two functions who works and control the thread, start() and abort()
void Worker::requestWork()
{
mutex.lock();
_working = true;
_abort = false;
qDebug()<<"Le thread travail de"<<this->myId<<" "<<thread()->currentThreadId();
mutex.unlock();
emit workRequested();
}
void Worker::abort()
{
mutex.lock();
if(_working) {
_abort = true;
qDebug()<<"Le thread "<<thread()->currentThreadId()<<" s'arrete";
}
mutex.unlock();
}
As you can see the workrequest emit a signal saying to the thread to start to work. And because the Worker Class is in the thread, how can I pause or restore it? From the worker class? from the MainWindow?
and now the Whole code.Mainwindow Class.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->lineEdit,SIGNAL(textChanged(QString)),this,SLOT(command(QString)));
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(valueChanged(QString)), ui->label, SLOT(setText(QString)));
connect(worker, SIGNAL(workRequested()), thread, SLOT(start()));
connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
}
//QLineEdit send signal to slot "command" permit to control the thread
void MainWindow::command(QString text){
qDebug()<<"le message a bien ete intercepte";
qDebug()<<ui->lineEdit->text();
if (text.contains("help"))
qDebug()<<"heeeelp";
if (text.contains("pause")){
worker->Paused();
if(thread->isRunning()){}
//cond.wait()
}
if (text.contains("restart")){
worker->Restarted();
if (!thread->isRunning()){}
//cond.wakeAll();
}
if (text.contains("stopped")){
worker->Paused();
thread->wait();
}
if (text.contains("start")){
worker->requestWork();
}
if (text.contains("destroyed")){
worker->destroyed();
}
}
So my question is: how to pause and restart the thread from the command() slot when the User insert "Pause" ?
I think you mess up the two possible ways of doing work with QThread:
One is to have an object (Worker) moved to a start()ed QThread. This way you do work by calling slots on the Worker, the work is done when the slots execute. You don't pause/resume this - when the slot is done, QThread will wait for new work, the same way QApplication waits for events when it's idle.
Second way is subclassing QThread, reimplementing run() and creating (some sort of) Worker there. Using this way you must create your "work queue" with something similar to your state variables (_working, _done, wait conditions, etc), because the thread will exit if it leaves run(), you must pause/resume yourself.

Wait until all threads are finished in main thread using Qt/C++

I want to make a condition in code to wait until all threads are finished in the main thread final slot, following is the test code ..
testClass::testClass()
{
m_count = 0;
m_flag = false;
for( int i = 0; i < 3; i++)
{
QThread *thread = new QThread();
WorkerThread *worker = new WorkerThread();
connect(thread, SIGNAL(started()), worker, SLOT(startThread()));
connect(worker, SIGNAL(workerFinished()), this, SLOT(threadFinished()));
connect(worker, SIGNAL(workerFinished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
m_workerList.append(worker);
}
}
void testClass::threadFinished()
{
// wait untill all thread are finished, how to achive this ?
if(!m_flag)
{
// print << m_flag;
m_flag = true;
}
}
void WorkerThread::startThread()
{
emit workerFinished();
}
here testClass is in main thread and I want the application to wait in threadFinished slot until all threads I started in testClass constructor to finish, could anyone suggest best way to do this ?
I am using Qt 5.4.0 in Windows 7.
If using boost in addition to Qt is an option, you can use a thread group and call join_all, which waits until all threads in the group are done.
Also, QThreadPool provides the waitForDone() function ("Waits for each thread to exit and removes all threads from the thread pool."), however you might have to restructure your worker objects slightly to comply to the QRunnable interface.
A more basic solution would be to set a QVector or QMap member variable with one entry for each thread and set them to true when the respective thread finishes. Continue program execution in your slot only when all threads have reached "finished = true" state in your member variable.

Threads that stay active (Qt)

I'm trying to correct a large program for memory leaks and threads that are not stopped. I know I have some, but I'm not sure about how to properly identify and kill them, so I started playing with some canonical examples, and I'm already having those.
First I tried the simplest thing:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
return a.exec();
}
That gives me one (1) running thread in the Task Manager.
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne *w = new WorkerOne();
QTimer::singleShot(3456, w, SLOT(stop()));
return a.exec();
}
This one gives me 1 before starting the worker, then 2 until the thread actually starts (process is called), then 3 until the singleShot signal is captured and the worker deleted and then 2 again. So I'm having something loose there.
And this is the code for WorkerOne:
WorkerOne::WorkerOne(QObject *parent)
: QObject(parent)
, m_stop(false) {
QThread* thread = new QThread;
this->moveToThread(thread);
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
WorkerOne::~WorkerOne() {}
void WorkerOne::process() {
while(!m_stop) {
QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); loop.exec();
}
emit finished();
}
void WorkerOne::stop() {
m_stop = true;
}
void WorkerOne::errorString(QString err) { }
The platform is Qt 5.2.1 with mingw48_32 compiler.
I think I am following the steps in threading howto from Maya Posch's blog, but maybe I am missing something.
Your implementation of the worker object is literally upside down. It's QThread's job to spin the event loop. Your worker object should simply be driven by slot calls and incoming events. A processing busy loop idiom uses a zero-length timer to stay active while allowing the event loop to receive events and quit, with no need for extra flags.
Here's how to do it:
class WorkerOne : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void processChunk() {
...
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) processChunk();
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() { m_timer.start(0, this); }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne worker;
QThread thread;
thread.start();
worker.start();
worker.moveToThread(&thread);
a.connect(&thread, SIGNAL(finished()), SLOT(quit()));
QTimer::singleShot(3456, &thread, SLOT(quit()));
return a.exec();
}
When the timer times out, the thread's event loop quits, the thread finishes, the application's event loop is quit, and, finally, the thread and the worker get destroyed.
A zero-length timer is not really a timer, just an idiom that means: invoke me as soon as the event loop is entered and there's nothing else to do. Doing the below would be a premature pessimization as there's be a memory allocation per each round through the event loop - not using the timer would be worse!
class WorkerOne : public QObject {
Q_OBJECT
Q_INVOKABLE void processChunk() {
...
// A lame attempt to call ourselves again from the event loop.
// It works, but has lot more overhead than a zero-length timer!
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() {
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
};