PDA

View Full Version : Deleting a thread content



Luc4
19th April 2010, 12:38
Hi! Is there any way to delete the content of a thread which is terminated using the terminate method? I tried to put a delete of the allocated variables of the thread after the terminate, even with a wait() in between, but the content (images for instance) are not deallocated. Any way to do this?
Thanks!

wysota
19th April 2010, 12:55
What do you mean by "content of the thread"?

squidge
19th April 2010, 13:20
The only way to do this is to ask the thread to terminate gracefully (and thus cleanup after itself) by sending it a kill signal rather than just killing it.

Luc4
19th April 2010, 13:34
Inside I have some pointers like QString* and QImage*, and I use the new operator to dynamically create objects. I need to delete these, but the delete only works when the thread exits from the run() function. If I terminate it, the delete instructions I placed in the GUI thread (not in the terminated thread) simply does nothing. This is what I placed in my GUI thread:


newThread->terminate();
delete newThread->pointer1;
delete newThread->pointer2;
...

I thought this could work but I was wrong. What has been created is not deleted. Any way to do this? I found this message but I don't know if it can be useful in this case: http://lists.trolltech.com/qt-interest/2001-02/thread00221-0.html.
Terminate gracefully means I should use the quit() method instead of terminate? How does it cleans up itself?
Many many thanks guys!

EDIT: Ok, maybe I was wrong... The problem is also related to a read() method of a QImageReader. It is local to the run() method, but I suppose, as you said, it remains there and can't be deleted unless I gracefully quit the thread. No other way to delete what remains after the termination?

wysota
19th April 2010, 14:14
QStrings and QImages shouldn't be kept as pointers at all. Change them to regular objects and all will be fine. And you should never call QThread::terminate(). That's just a failsafe if you have to kill a thread and don't care about anything else.

Luc4
19th April 2010, 14:31
OK, but I suppose we would be back to the problem you helped me with in the thread http://www.qtcentre.org/threads/29687-Loading-an-image-into-memory?highlight=. If I terminate the thread, it seems I can stop the read method, otherwise my thread finishes the loading. I tried using the quit() method, and in that case everything is right, like you said. Unfortunately, I have to wait many seconds till the image is completely loaded.

wysota
19th April 2010, 14:55
You can't eat the cake and still have the cake. QImage was just not meant to be interrupted while loading. You can use lower level calls by wrapping libjpeg/libpng and others yourself instead of going through QImage.

Nik8768
20th April 2010, 01:21
QStrings and QImages shouldn't be kept as pointers at all.

why not?
do you mean inside thread.. or in general?

Luc4
20th April 2010, 08:35
I was about to ask the same as well. Moreover, I can't find anything about deleting a thread, except for that link I reported before. If I create a thread by using the new operator, do I have to delete that thread after it has finished using the delete operator? Is it possible to use delete this as the last instruction of the run() method?
Thanks!

wysota
20th April 2010, 10:13
why not?
Because there are no benefits of keeping pointers as both these classes are implicitly shared and value-based.

do you mean inside thread.. or in general?
In general.

wysota
20th April 2010, 10:15
I was about to ask the same as well. Moreover, I can't find anything about deleting a thread, except for that link I reported before. If I create a thread by using the new operator, do I have to delete that thread after it has finished using the delete operator? Is it possible to use delete this as the last instruction of the run() method?
Thanks!

QThread object is not a thread. It's just an object that let's you start a thread. Only the contents of the run() method are ran in the worker thread. So it's enough to return from run() and the thread will end. Of course you still have to do something with the QThread object, but there is nothing special about it - it's a QObject like any other.

faldzip
20th April 2010, 11:21
QThread object is not a thread. It's just an object that let's you start a thread. Only the contents of the run() method are ran in the worker thread. So it's enough to return from run() and the thread will end. Of course you still have to do something with the QThread object, but there is nothing special about it - it's a QObject like any other.

So good solution is to make local variables in the run() method (for example instead of member variables if it is possible) so they are created in new thread and deleted when this thread ends (it ends when run() ends). So such local thread data is self cleaned on thread finish. Tadam! :]

wysota
20th April 2010, 11:38
So good solution is to make local variables in the run() method (for example instead of member variables if it is possible) so they are created in new thread and deleted when this thread ends (it ends when run() ends). So such local thread data is self cleaned on thread finish. Tadam! :]

Yes, exactly. And if you need to expose signals and slots outside you can do it like so:

class Thread : public QThread {
public:
const Object *myInterface() const { return m_iface; }
void run() {
Object o; // lives in the worker thread, declares signals and slots
m_iface = &o;
//...
exec();
}
private:
QPointer<Object> m_iface;
};

... or the other way round (which is better as it doesn't force you to know when the thread starts):


class Thread : public QThread {
public:
void setInterface(Object *o) { m_iface = o; }
void run() {
if(!m_iface) return; // refuse to run without the interface
Internal i;
connect(m_iface, SIGNAL(...), &i, SLOT(...)); // "m_iface" lives in the main thread, "i" lives in the worker thread
connect(&i, SIGNAL(...), m_iface, SIGNAL(...)); // propagate signal outside
//...
exec();
}
private:
QPointer<Object> m_iface;
};

Of course in the second case the QThread object can serve as "m_iface".

Luc4
20th April 2010, 19:15
QStrings and QImages shouldn't be kept as pointers at all. Change them to regular objects and all will be fine. And you should never call QThread::terminate(). That's just a failsafe if you have to kill a thread and don't care about anything else.

And regarding the use of pointers or regular objects, what would be the best way to load the image in case I want later to get that image and render it in my GUI thread? What I do now is use a pointer in my loader thread which does something like:


QImageReader(path);
image = new QImage(imageReader.read());

and then I show the image in my GUI thread in a label with:


QPixmap pixmap = QPixmap::fromImage(loaderThread->image);
label->setPixmap(pixmap);
...

As far as I can understand, this creates the QImage once in the read() method, then it creates another QImage in the heap and assigns the pointer. Then, again, I create the QPixmap which is again copied inside the label. Is this correct? Does this code really creates so many copies of the image? Would it be possible to do it quickly and smartly?
Thanks again for your advices!

wysota
20th April 2010, 19:21
I can't think of any sane usecase where it would be necessary to allocate a QImage using the "new" operator. QImage is just like "int" - when would you allocate a single int using "new"?

Luc4
20th April 2010, 19:44
mmh... would you use a simple object QImage in the loader thread and then assign?

image = imageReader.read();
my doubt is that I can start again the thread which should load another QImage. So, if in the following run of my thread I have another:

image = imageReader.read();
is the previous image that was stored in the object deleted? I suppose this is a C++ doubt :p
Thanks for your help!

wysota
20th April 2010, 20:07
mmh... would you use a simple object QImage in the loader thread and then assign?
Yep.


my doubt is that I can start again the thread which should load another QImage.
It doesn't matter. QImage is an implicitly shared class. It will detach itself from all shared copies once you try to change its contents.


is the previous image that was stored in the object deleted?
It is "deleted" (not actually deleted but let's assume this is the case) if it was the only QImage object attached to the data contained in it. If there is another variable holding the same image, it will remain assigned to the other variable.

I suggest you read a bit about "implicit sharing" in Qt - things will become clear then.

Luc4
21st April 2010, 08:39
This is awesome! Everything is clear now! Thanks for addressing me to that document!