[Solved] Can't stop my own thread from the main thread
-
Thank you so much for your answer! I tried to change my code and used the link you gave to me. But still it doesn't work the way I want it. And I'm very sorry, but I didn't understand about Thread->exit(). In the link you gave above nothing was told about this function and its use. I read the documentation several times, but didn't undestand the difference between quit() and exit(), except quit() is a slot and exit() is a function. So...now my code in the mainwindow.cpp looks like that:
@QProgressDialog *ProgressDialog=new QProgressDialog(QObject::trUtf8("Updating"),QObject::trUtf8("Stop"),0,100, this);
QThread *thread=new QThread();
worker=new LoadingWorker();
worker->setFile(updateforuserDialog.getFileName());
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(LoadingProcess()));connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(worker,SIGNAL(ValueChanged(int)),ProgressDialog, SLOT(setValue(int)));
connect(worker,SIGNAL(finished()),SLOT(MessageSlot()));
connect(ProgressDialog,SIGNAL(canceled()),this, SLOT(AskUserUpdating()));
ProgressDialog->show();
thread->start();@ -
First of please change this line (line 11 in the code snippet above):
@
connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()));
@
to this
@
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
@Secondly: To be able to cancel the work executed in the second thread you need to implement a slot for your worker object which will stop the processing in your LoadingProcess() slot when triggered. Then you can connect a signal (e.g. clicked() signal from PushButton) to this slot.
But be aware that the slot stopLoadingProcess() or whatever you may call it is only execute when you return back to the eventloop in between your LoadingProcess() slot. -
By saying " slot stopLoadingProcess() or whatever you may call it is only execute when you return back to the eventloop " you mean I won't be able to stop the LoadingProcess while it is being executed by my own thread?Very sorry to ask the same questions, but it seems very complicated to me:=) I undestand that the signal is delayed cause the object WORKER belongs to the different thread. So, how to make this signal connect with the slot stopLoadingProcess() at the same moment I press cancel?...What should I do? I mean what is the point of creating stopLoadingProcess() slot if it doesn't work at the time I need it. Thank you very much for your help!=)
-
Exactly. Thats why you need to return to the eventloop in between the execution of the LoadingProcess slot.
Example:
@
void LoadingWorker::stopLoadingProcess()
{
m_bCancelExecution = true;
}// this never returns to the eventloop during execution
void LoadingWorker::LoadingProcess()
{
//updating my database
for(int i = 0; i < someSize; ++i)
{
if(!m_bCancelExecution)
{
processEntry(i);
}
}
emit finished();
}// this returns in between each step
void LoadingWorker::LoadingProcess()
{
if(!m_bCancelExecution)
{
//updating my database
if(m_iCounter < someSize)
{
ProcessEntry(m_iCounter);
m_iCounter++;
QTimer::singleShot(100, this, SLOT(LoadingProcess()));
}
else
{
m_iCounter = 0;
emit finished();
}
}
}
@ -
I was just giving an example of a function in a worker object which does not return back to the eventloop during its work and a function which does return.
If you want to be able to stop your worker object while its doing its heavy processing stuff you need to return to the eventloop in between the processing(see second example). Otherwise the slot stopWork() or whatever will only be called after all the work is done (which is not what you want)
-
Yes, I understood that.Thank you)But even with your example I can't understand how I can get to the eventloop in the middle of the process. My slot is quite big and I don't see how exactly I can use your example with my own slot. A schematic code of my slot is
@if (file->open(QIODevice::ReadOnly | QIODevice::Text))
{
some code..
while(i<= k)
{
some code..
i++;
}
some code..
while(i<= n)
{
some code..
i++;
}
some code...
while(i<= m)
{
some code..
i++;
}
file->close();
emit finished();
}@Very sorry.Thank you so much!
-
Example:
@
void LoadingWorker::LoadingProcess()
{
if (file->open(QIODevice::ReadOnly | QIODevice::Text))
{
newFunction1();
}
}void LoadingWorker::newFunction1()
{
if(!m_bCancelExecution)
{
some code..
while(m_iCounter<= k)
{
some code..
m_iCounter++;
}
QTimer::singleShot(10, this, SLOT(function2()));
}
else
{
file->close();
emit finished();
}
}void LoadingWorker::newFunction2()
{
if(!m_bCancelExecution)
{
some code..
while(m_iCounter<= n)
{
some code..
m_iCounter++;
}
QTimer::singleShot(10, this, SLOT(function3()));
}
else
{
file->close();
emit finished();
}
}void LoadingWorker::newFunction3()
{
if(!m_bCancelExecution)
{
some code...
while(m_iCounter<= m)
{
some code..
m_iCounter++;
}
file->close();
emit finished();
}
else
{
file->close();
emit finished();
}
}
@Again this is just an example. You could divide this even further if you want to check for the boolean flag in the while loops by using something like the recursive approach I described in an example previously.
Example:
@
void LoadingWorker::newFunction1()
{
if(!m_bCancelExecution)
{
if(m_bFirstTimeInFunction1)
{
some code..
m_bFirstTimeInFunction1 = false;
}if(m_iCounter<= k) { some code.. m_iCounter++; QTimer::singleShot(10, this, SLOT(function1())); } else { QTimer::singleShot(10, this, SLOT(function2())); }
}
else
{
file->close();
emit finished();
}
}
@
You can also emit a signal instead of using QTimer::singleShot() but make sure to use QueuedConnection in the connect statement. -
Just thought of another solution to your problem. You can use "QCoreApplication::processEvents()":http://qt-project.org/doc/qt-5.0/qtcore/qcoreapplication.html#processEvents to force your thread to return to the event loop. Just make sure you don't call it too often, otherwise it might slow down your processing.
processEvents has some pitfalls so make sure you avoid them. For more information about it just "search for processEvents on this site":http://qt-project.org/search?search=processEvents.
Example:
@
if (file->open(QIODevice::ReadOnly | QIODevice::Text))
{
some code..
QApplication::processEvents();
while(i<= k)
{
some code..
i++;
QApplication::processEvents();
}
some code..
QApplication::processEvents();
while(i<= n)
{
some code..
i++;
QApplication::processEvents();
}
some code...
QApplication::processEvents();
while(i<= m)
{
some code..
i++;
QApplication::processEvents();
}
file->close();
emit finished();
}@