Who deletes object created in worker thread?



  • In my code, worker thread creates object A, main thread class B destructor calls worker thread's destructor, object A is deleted in worker thread's destructor.
    the code is like:
    @
    WorkerThread::foo() {
    Object *p = new Object;
    }

    WorkerThread::~WorkerThread {
    delete p;
    wait();
    }

    B::~B() {
    emit signal();
    //this signal is to ask worker thread to quit,
    //the signal/slot connection is connect(this, SIGNAL(signal()), mWorkerThread, SLOT(quit()));
    delete mWorkerThread;
    }
    @
    Now the problem is worker thread's other function may be still using *p (object A). I know I can add mutex at WorkerThread destructor. But sometimes I got error message saying that object A should not be deleted in the thread which didn't not create it. Does this mean I need to delete *p in worker thread? how do I make it work? use another signal and slot?

    Thanks,

    [Edit: Added @ tags and fixed formatting of code -- mlong]



  • If the class Object is derived (directly or indirectly) from QObject and is a member of WorkerThread you can just set WorkerThread as its parent. This way the instance of Object will be deleted automatically when the instance of WorkerThread which created it is deleted. But be aware that in this case the Object instance is living in the same context as the WorkerThread instance, which is the context of the main thread.

    [quote author="justDance" date="1358282701"]
    Now the problem is worker thread's other function may be still using *p (object A).
    [/quote]
    This can not be true if you're calling delete in WorkerThreads destructor and Object is not derived from QObject. If it inherits QObject just call deleteLater instead of delete.

    The main problem is that you should not call delete on the WorkerThread, but you should rather call deleteLater() (assuming WorkerThread is derived from QThread). This is because QThread does some internal magic before shutting down and if you call delete directly the instance of WorkerThread is deleted but might still be used somewhere.

    [quote author="justDance" date="1358282701"]
    But sometimes I got error message saying that object A should not be deleted in the thread which didn’t not create it
    [/quote]
    This is because you have created the instance in a function which is called from the run function of your WorkerThread (i.e. in the context of the thread managed by your WorkerThread). So you have to delete it in the context of that same thread. But since the WorkerThread object itself is created in the context of the main thread its destructor is also running in the context of the main thread.

    I suggest you follow my advice from "this post":http://qt-project.org/forums/viewthread/23389/#109154 and DO NOT SUBCLASS QTHREAD. The problems you are experiencing at the moment are common pitfalls of the subclassing approach with QThread, please try the "worker object approach":http://qt-project.org/wiki/QThreads_general_usage, you will see that it is way easier to handle. "The official documentation for QThread also discourages the use of the subclassing approach":http://qt-project.org/doc/qt-4.8/qthread.html#subclassing-qthread.

    Quote from official docs:
    [quote]
    It is important to remember that a QThread object usually lives in the thread where it was created, not in the thread that it manages. This oft-overlooked detail means that a QThread's slots will be executed in the context of its home thread, not in the context of the thread it is managing. For this reason, implementing new slots in a QThread subclass is error-prone and discouraged.[/quote]



  • Thanks KA510.
    I looked at http://qt-project.org/wiki/QThreads_general_usage.
    It's very helpful.
    But in my case, it is main thread to decide when to delete workerThread, it means I don't have any function like process() to emit finished to inform itself to delete itself.
    I guess what I can do is to connect a signal from main thread to workerThread's finished signal. Then everything should work the same as the example in the link.



  • also in http://qt-project.org/wiki/QThreads_general_usage, the worker thread only needs to call process() to do specific work. But in my case, worker thread has to have event loop.
    what I have now is as following, but it has problems I mentioned before. so now my question is when I follow the example, how can I run exec()?

    @ WorkerThread::WorkerThread() {
    start();
    moveToThread(this);
    }

    void WorkerThread::run() {
    exec();
    }@


  • I guess I don't need to call exec() explicitly. just follow the example in http://qt-project.org/wiki/QThreads_general_usage,
    @ thread->start();@
    will run the thread and call exec().



  • [quote]
    I guess I don’t need to call exec() explicitly. just follow the example in http://qt-project.org/wiki/QThreads_general_usage,

       thread->start();
    

    will run the thread and call exec().[/quote]

    Correct. Thats the beauty of it. Since Qt version 4.4 the default implementation of QThreads run function calls exec(), so you have a running eventloop.

    The benefit of the worker object approach is that you just do all the stuff you want to do in a worker class. It doesn't matter if this class runs in the context of your main thread or another thread, just make sure all the communication to other objects is happening via signals and slots (starting, pausing, stopping, handing over data,..). Once you have this done you just need to move the object to a QThread and start that thread. All the operations the worker object is doing are now done in this separate thread.
    Now if you want to stop or terminate the worker object and the thread you just need to have a slot in your worker object that handles a signal from the main thread so that the worker stops his job and signals his worker thread to quit and calls deleteLater on himself and so on (see the connection calls in the QThreads general usage article)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.