PDA

View Full Version : Terminating QThread error



ramazangirgin
29th July 2008, 11:33
i have a thread which does long operation. while its operates i want to terminate thread. The thread isn't in loop.
I have tried QThread::terminate() and QThread::wait() methods. But sometimes my program is freezing at QThread::terminate() method.
I have searhed the forum. There is another way for this is using flags but i can't interfere in loop of thread because i am calling another function from external lib.
Is there any other way for terminating thread.
Thanks in advance
Ramazan

TheKedge
29th July 2008, 13:24
You can use terminate() but nobody recommends doing that.

What you should do is intersperse a control variable throughout your job - and break your job into small parts.

So, when you sub-class QThread you should make a private variable :
bool keepRunning;
and rewrite stop() to include keepRunning = false;
then your run() looks like this...

run()
{
keepRunning = true;
//do some stuff
if(!keepRunning) return;
//do more stuff
if(!keepRunning) return;
//do even more stuff
//etc
}


here's my stop():

//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++
/// wrapper for stopping the thread gracefully
//++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++
bool BaseDevice::stop (unsigned long time )
{
keepRunning = false;

QThread::quit();
return QThread::wait(time);//returns false if timedout
}

nooky59
21st August 2008, 15:07
You can use terminate() but nobody recommends doing that.

What you should do is intersperse a control variable throughout your job - and break your job into small parts.


I wake up this post as I have such a problem. I dealt with it on Windows by using an ugly construct with terminate() but on Linux / OS X, it makes a beautiful segmentation fault.

As the original writer of this post said, this is not already possible to break a task in several parts, especially if you are using an external library.

This is my case as I use gSOAP. My application is multi-windows relying on a static QModel shared between the windows. When the last windows is closed (the app is stil runing in the systray), the model is destroyed, so the thread owned by the QModel is destroyed as well.

I've tried a clean code like in Qt samples with a wait() call.

But, as I have simulated slow connections, wait() could freeze the application for 10 or 20 seconds before the thread is destroyed and the app won't react to sollicitations (new window opening when double-clicking on the systray nor contextual systray menu as well).

So is there other solutions ?

My idea is to use a timer or other thread that could be notified when a worker thread should be destroyed after it has finished his job. In this way, the timer or monitoring thread could asked periodically to the worker thread if it has finished running then be deleted when it is ok.

nooky59
21st August 2008, 16:46
Hmmm it seems my idea is hard to implement has it seems that Qt doesn't like to interact with a QMutex in a dynamically created thread, both statically and dynamically

nooky59
22nd August 2008, 09:44
Nobody has a solution ?

It is really important for the application not to crash and still reacting (so not waiting for the thread termination that depends on the gSOAP ending its HTTP call) when I close a windows.

I can't use on the heap allocation for the threads because Qt doesn't really like that (I've got error messages related to QMutex).

The problem is really with the terminate() call that works on Windows but leads to a segmentation fault on an UNIX system.

wysota
22nd August 2008, 10:03
Using terminate() is Bad(TM) because you never know what is the current state of the thread when you try terminating it and the best that can happen is to get a segfault :)

I don't know what you want to use mutexes for, but if it doesn't work then you must have done something wrong - QThread and QMutex work quite well with each other regardless of how the thread is created.

Is your application a soap server or a soap client? Can't you check a stop variable in soap code and terminate the request when you see a raised flag?

nooky59
22nd August 2008, 11:35
Yes, I know that it is bad and this is clearly told in the Qt documentation. But when you have no other choice...

In any case, I've found the solution to avoid the crash on UNIX systems.

But let's answer to your questions first.

In fact, my thread use the same construct as the mandelbrot example for example so there is a QMutex protecting access to members variables in the same way.

What I told in my previous posts is that I had tried to do stuffs like :

MyThread *thread = new MyThread();

In this way, I thought I could have started a timer in the QApplication class from the destructor of thread's parent but it doesn't work if you have mutexes in the thread.

If you have an "on the stack" QMutex, Qt will complain about a pointer alignement problem. If you have an "on the heap" QMutex, you will have access violation.

My application is a soap client but as it is multi-windows, I don't want an user with a slow connection closing a window then crashing the app or freezing the app until the result of the gSOAP call.

But I have the solution, I've put this in the thread destructor :



MyThread::~MyThread()
{
mutex.lock();
quit = true;
cond.wakeOne();
mutex.unlock();

wait(100);
if(isRunning())
{
terminate();
wait(); // needed for UNIX systems
}

delete service;
}

From the mandelbrot sample, the difference is I put 100 ms for the wait so after 100 ms, if the thread is not terminated, the evil terminate() call is triggered.

It was perfect on Windows, not on Linux / OS X. But by adding a second wait() as told in the Qt documentation :

"Use QThread::wait() after terminate() for synchronous termination."

it is now perfect.

I don't have conflict with the state of my thread indeed because if this is a writing soap call, I forbid the window closing, I let the user doing it only if it is a read access so no problem.

wysota
22nd August 2008, 11:45
In this way, I thought I could have started a timer in the QApplication class from the destructor of thread's parent but it doesn't work if you have mutexes in the thread.
I don't really understand what you mean.


If you have an "on the stack" QMutex, Qt will complain about a pointer alignement problem. If you have an "on the heap" QMutex, you will have access violation.
What is the exact code you used?


My application is a soap client but as it is multi-windows, I don't want an user with a slow connection closing a window then crashing the app or freezing the app until the result of the gSOAP call.
Can't gSOAP make asynchronous calls? Anyway gSOAP call hangs on some system call like read and you can send a signal to cause it to return immediately with EINTR. Then you'll be able to shut down the thread.


But I have the solution, I've put this in the thread destructor :
Still, using terminate is dangerous. Of course if your application doesn't do anything serious, consequences will also be minimal.

nooky59
22nd August 2008, 13:15
I don't really understand what you mean.


What is the exact code you used?


I tried to reproduce it on the mandelbrot sample and I had no problems. Then, I've thought immediately where I could have done a mistake previously (even if I didn't keep the tried code) !!!

MyThread *thread = new MyThread();

in the constructor of my class !!! I instanciate a local object to my constructor rather than using the member :

thread = new MyThread();

I was quite tired, sorry !



Can't gSOAP make asynchronous calls? Anyway gSOAP call hangs on some system call like read and you can send a signal to cause it to return immediately with EINTR. Then you'll be able to shut down the thread.


I haven't seen such a thing in the documentation. You can use asynchronous call only for one way messages so if you don't need an answer.

You can only deal with time-out but this is not a solution I want for the reactivity of my app.

Moreover, the documentation say :

---
Caution: Many Linux versions do not support non-blocking connect(). Therefore, setting soap.connect_timeout for non-blocking soap_call_ns__method calls may not work under Linux.
---



Still, using terminate is dangerous. Of course if your application doesn't do anything serious, consequences will also be minimal.


I will listen to you even if it works now and if I think there could not conducts to problems (but the application does something serious because it deals with customers data).

Now that I have found my mistake regarding on the heap QThread allocation, I could manage myself when the thread should be destroyed.

So if the QThread's theorical parent (I won't give this to the QThread constructor to avoid cascading deletion process of Qt) is to be destroyed, I could now launch a monitoring code in the QApplication object, from the QThread's parent destructor that will destroyed the thread after it has properly terminate his job.

Thanks for your answers and to tell me that it is still very bad to deal with evil ;o)

wysota
24th August 2008, 18:18
(but the application does something serious because it deals with customers data).
In that case I'd look for a safer solution.


Thanks for your answers and to tell me that it is still very bad to deal with evil ;o)

Mmm... easy the Dark Side seems to be... Once the path you enter, not able to withdraw you will be even if to senses quickly you come back, young padawan...