I'm trying to create a program using threads:
the main start with a loop.
When a test returns true, I create an object and I want that object to work in an other thread
then return and start the test .
QCoreApplication a(argc, argv);
while(true){
Cmd cmd;
cmd =db->select(cmd);
if(cmd.isNull()){
sleep(2);
continue ;
}
QThread *thread = new QThread( );
process *class= new process ();
class->moveToThread(thread);
thread->start();
qDebug() << " msg"; // this doesn't run until class finish it's work
}
return a.exec();
the problem is when i start the new thread the main thread stops and wait for the new thread's finish .
The canonical Qt way would look like this:
QThread* thread = new QThread( );
Task* task = new Task();
// move the task object to the thread BEFORE connecting any signal/slots
task->moveToThread(thread);
connect(thread, SIGNAL(started()), task, SLOT(doWork()));
connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));
// automatically delete thread and task object when work is done:
connect(task, SIGNAL(workFinished()), task, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
in case you arent familiar with signals/slots, the Task class would look something like this:
class Task : public QObject
{
Q_OBJECT
public:
Task();
~Task();
public slots:
// doWork must emit workFinished when it is done.
void doWork();
signals:
void workFinished();
};
I don't know how you structured your process class, but this is not really the way that moveToThread works. The moveToThread function tells QT that any slots need to be executed in the new thread rather than in the thread they were signaled from. (edit: Actually, I now remember it defaults to the tread the object was created in)
Also, if you do the work in your process class from the constructor it will not run in the new thread either.
The simplest way to have your process class execute in a new thread is to derive it from QThread and override the run method. Then you never need to call move to thread at all.
Related
I have a simple QObject:
class Engine : public QObject
{
Q_OBJECT
public:
explicit Engine(QObject* parent = 0);
signals:
void finished();
public slots:
void start();
};
An instance Engine* engine is stored inside the main window class. When a button is pressed, the following happens:
QThread* thread = new QThread;
engine->moveToThread(thread);
connect(engine, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), engine, SLOT(start()));
connect(engine, SIGNAL(finished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
My question is, what happens to engine after thread finishes? Can I create another thread and move engine to that thread, and repeat everything again?
What happens to engine after thread finishes?
What happens with the object is independent of it being moved to a thread. When you "move" you are not doing a real move, you are just telling to execute some of the code on a thread. The object will get destroyed as usual (out of scope or delete for heap allocated).
Can I create another thread and move engine to that thread, and repeat
everything again?
Yes, as long as the object still exists.
This is part of the main.
This code create a worker and a workerthread.
The worker is moved to the workerthread.
The worker is then waiting for the signal to ask it to work.
The worker emit a signal with result when job done.
The main supposed to catch that signal and initialize a variable in the main.
main()
{.........
// This is the variable to be changed
variableToGetFromWorker = 0;
qDebug() << "Main thread: " << QThread::currentThreadId();
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
workerThread.start();
workerThread.wait();
...........}
// This is a slot at main. Suppose to catch the signal from the worker
void main::jobDone(int result)
{
qDebug() << "Changing variable";
variableToGetFromWorker = result;
}
This is the doJob slot of the worker.
void worker::doJob()
{
qDebug() << "worker::doJob invoked.";
qDebug() << "worker Thread:" << QThread::currentThreadId();
// Doing Job here
emit jobDone(result);
}
It is the qDebug result
Main thread: 0x7ffff7fc6780
worker::doJob invoked.
worker Thread: 0x7fffdab44700
In Debug mode, I find that the program is stop at workerThread.wait()
and never go to main::jobDone(int result). What is the reason?
Little editing on the main code:
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
connect(stupidTom, SIGNAL(jobDone(int)), &workerThread, SLOT(quit()));
workerThread.start();
workerThread.wait();
As long as signals supposed to invoke slots. That won't be working on wait() on the main thread that supposed to run the slot or specifically jobDone signal.
Make sure to understand the difference between QThread::exec() and QThread::wait() in your application. Normally in the real app your thread would be looping (running) while the thread that launched it is still looping as well. The loop is implemented in protected QThread::exec() method. We usually don't need to call exec() explicitly but we need to allow the thread to run. You can do that by making main function to use QEventLoop for looping:
int main()
{
//...
workerThread.start();
QEventLoop eventLoop;
// here you will probably want to hook-up QEventLoop::quit() slot
// to eventually quit the process
int returnCode = eventLoop.exec();
//...
return returnCode;
}
And this is also wrong:
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
Instead you should create your own job object and do QObject::moveToThread for it. Here is a nice article about it. So it should rather look like:
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
I likely understand why you attempted to run the thread that way as above. It is similar to many C++ examples. You can also do that in Qt but you also need to realize how exactly you'll be waiting on completion of workerThread. And Qt most popular way to do the interaction between threads is with signals and slots. That is why we should use QEventLoop in main. But of course there is an alternative. For lower level plain C++ you can use mutex and condition variable to accomplish the same. Or that same wait() but then there is no signals involved.
Also watch the debug output, whether or not all the connect statements really connect proper signals to slots. In case if there is no connect it prints the warning.
I have a problem where I am looking to create a processing class, and I want to feed data into it, then put it into a thread, and tell it to start working. Currently, this is what I have to do that:
ProcessingClass *worker = new ProcessingClass(myData);
connect(this, SIGNAL(startWorking()), worker, SLOT(startWorking()));
connect(worker, SIGNAL(doneWorking(data)), this, SLOT(workerFinished(data)));
QThread *workerThread = new QThread;
worker->moveToThread(workerThread);
workerThread->start();
emit(startWorking());
What this ends up doing is it creates the worker, gives it the data that I want it to process, connects what needs to be connected for everything to work, moves it on over to its thread, and then emits the signal to start working. This more or less does what I want it to, but there is an issue. Namely, I want to be putting this into a loop:
while (reason){
...//gathering data to give to the worker
ProcessingClass *worker = new ProcessingClass(myData);
connect(this, SIGNAL(startWorking()), worker, SLOT(startWorking()));
connect(worker, SIGNAL(doneWorking(data)), this, SLOT(workerFinished(data)));
QThread *workerThread = new QThread;
worker->moveToThread(workerThread);
workerThread->start();
}
emit(startWorking());
This does accomplish what I want it to do, but it does so by sticking everything in memory, waiting until it is all there, and then set off every single thread simultaneously to compete for resources until they are all done. Considering that for my current data amount this is over 1000 different threads, each of which takes (from previous iterations of this program) ~1-2 minutes to process the information, and the last version crashed because it ran out of memory (I think...) I don't particularly like this method much anymore.
What I would like to do is figure out a way to move the resources that I want to the thread, and then set off the thread to do the work immediately. Then I want to be able to pause the loop after some amount of threads are running (so as to not overload the computer again) and then continue this loop and set off the next thread after one of the previous threads is done.
Is there a nicer way to accomplish this?
You should have a fixed number of worker threads, and iterate the loop only when there are threads that are not busy.
If you insist on using a QObject, you can create a QRunnable wrapper to run the worker objects until completion in a thread pool, and to track their progress to issue more work:
class ProcessingRunnable : public ProcessingClass, public QRunnable {
void run() Q_DECL_OVERRIDE {
QEventLoop loop;
moveToThread(QThread::currentThread());
QMetaObject::invokeMethod(this, "startWorking", Qt::QueuedConnection);
loop.exec();
moveToThread(0);
}
public:
explicit ProcessingRunnable(const Data & data) :
ProcessingClass(data) {
setAutoDelete(false);
moveToThread(0); // we will be moved to a worker thread later
}
};
class JobManager : public QObject {
Q_OBJECT
QThreadPool m_pool;
QScopedPointer<ProcessingRunnable> m_worker;
int m_jobs;
public:
Q_SIGNAL void allJobsFinished();
Q_SLOT void runJobs() {
while (true) {
if (m_worker) {
if (m_pool.tryStart(m_worker.data())
m_worker.take();
else
break;
}
}
if (! reason) break;
... // gather data to give to the worker
m_worker.reset(new ProcessingRunnable(myData));
++ m_jobs;
connect(m_worker, &ProcessingRunnable::doneWorking, [this]{
-- m_jobs;
runJobs();
if (! m_jobs) emit allJobsFinished();
});
}
}
explicit JobManager(QObject * parent = 0) : QObject(parent),
m_jobs(0) {
}
}
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
...
JobManager manager;
QObject::connect(&manager, &JobManger::allJobsFinished,
&app, &QCoreApplication::quit, Qt::QueuedConnection);
manager.runJobs();
...
return app.exec();
}
For this kind of an application, it might be simpler to make your ProcessingClass be a simple functor, not a QObject, and use QtConcurrent::Run and QFutureWatcher.
My code is too long to post, here is the related part:
videoClass::videoClass()
{
...
QThread* workerThread = new QThread(this);
camwrk = new cameraWorker(workerThread);
camwrk->moveToThread(workerThread);
// There are many cross thread signal slot connections happening between this and the camwrk
}
videoClass::~videoClass()
{
...
delete camwrk;
...
}
cameraWorker::cameraWorker(QThread* workerThread)
{
_belongingThread = workerThread;
...
}
cameraWorker::cameraWorker(QThread* workerThread)
{
_belongingThread = workerThread;
...
}
cameraWorker::~cameraWorker()
{
_belongingThread->quit();
_belongingThread->wait();
}
Everytime when the _belongingThread->wait(); is finished, I got the message:
QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread
What is happening here? I thought this is the correct way to use a QThread and finish it?
The QThread object itself belongs to the main thread:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run().
Apparently, QThread::wait() is implemented via events. Since cameraWorker itself is running on workerThread and not on videoClass's thread, you can't use it.
That being said, your current logic seems a little bit too complicated. You want to stop the thread when the cameraWorker gets destroyed, and you want to destroy the camera worker when its parent gets destroyed too:
QThread* workerThread = new QThread(this);
connect(camwrk, SIGNAL(destroyed()), workerThread, SLOT(quit()));
connect(this, SIGNAL(destroyed()), camwrk, SLOT(deleteLater()));
If you want to delete the workerThread after it's finished its execution simply connect finished() and deleteLater():
connect(workerThread, SIGNAL(finished()),
workerThread, SLOT(deleteLater()));
However, keep in mind that ~videoClass() will call the destructor of workerThread. Make sure that the thread doesn't run anymore before the object gets destroyed, or simply remove this from new QThread(this) to prevent ownership.
I have done an application with some threads. Everything seems to work ok if I call my stopConsumer inside a keypressedEvent. But If I call it inside a destructor of closeEvent.. it fails.
My QThread class that has a run method like this one:
void Consumer::run()
{
forever {
// do something something
// do something something
// do something something
//-------------------------------- check for abort
abortMutex.lock();
if(abort) {
abortMutex.unlock();
qDebug() << "abort..";
break;
} abortMutex.unlock();
//-------------------------------- check for abort
}
qDebug() << "Consumer > emit finished()";
emit finished();
}
void Consumer::stopConsume() {
abortMutex.lock();
abort = true;
abortMutex.unlock();
}
and a method in the MainWindow:
void initConsumers()
{
consumer1 = new Consumer(....);
connect(consumer1, SIGNAL(finished()),
this, SLOT(deleteConsumer()));
consumer1->start();
}
void stopConsumer() {
if(consumer1!=NULL) {
qDebug() << "stopConsumer";
consumer1->stopConsume();
}
}
If I have a keypressed that calls stopConsumer.. it's ok, deleteConsumer is reached.
If I call stopConsumer inside the MainWindow destructor or inside a MainWindow closeEvent.. the slot deleteConsumer is never reached!
Any ideas?
Given that the Consumer class and your MainWindow have different thread affinities, the call you make to connect inside initConsumers() is likely using a Qt::QueuedConnection, which means that the deleteConsumer() slot won't get called immediately.
If you would like to ensure that the consumer gets deleted from the destructor of your main window (or equivalently, from a close event), one possible solution is to call stopConsume() on the consumer, then wait until the thread is no longer running (see http://qt-project.org/doc/qt-5.1/qtcore/qthread.html#isRunning), then call deleteConsumer() directly.
Update
Here's an example of what I described above:
consumer1->stopConsume();
consumer1->wait();
deleteConsumer();
It's not advisable to switch the connection type to Qt:DirectConnection since that will cause the deleteConsumer() function to be called from the body of Consumer::run(), which will likely crash your application.
Part of the problem here is that you're deriving from QThread, which is not how it is supposed to be used. You can read about why deriving from QThread is wrong here.
Instead, what you should be doing is deriving your class from QObject, creating a QThread object and moving the derived QObject instance to that thread.
class Consumer : public QObject
{
...
signals:
void finished();
private slots:
void run();
}
QThread pThread = new QThread;
Consumer pObject = new Consumer;
// move the pObject to the thread
pObject->moveToThread(pThread);
You can then control the thread with signals and slots.
// assuming you've added a run slot function to the Consumer class
connect(pThread, SIGNAL(started()), pObject, SLOT(run()));
connect(pObject, SIGNAL(finished()), pThread, SLOT(quit()));
connect(pObject, SIGNAL(finished()), pObject, SLOT(deleteLater()));
// Note the thread cleans itself up here, but if the app is quitting,
// waiting on the thread to finish may be required instead
connect(pThread, SIGNAL(finished()), pThread, SLOT(deleteLater()));
And start the thread: -
pThread->start();
Used this way, it also enables multiple objects to be moved to a single new thread, rather than creating a new thread per object instance.