Results 1 to 5 of 5

Thread: QThread slots not executed in created thread context?

  1. #1
    Join Date
    Mar 2011
    Posts
    5
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default QThread slots not executed in created thread context?

    Hello All,

    I'm having some difficulty getting slots residing in a QObject class that has been moved into a thread to actually execute in a separate thread.

    I have read quite a bit on this, and found most examples, including the one here (http://labs.qt.nokia.com/2010/06/17/...oing-it-wrong/) to be slightly simplified....or at the very least different than my program.

    I have (essentially) a UI that displays streaming video. The video is received from the camera, processed and marked up. It is then finally displayed on the UI (on a QLabel). The system is 100% functional. However, I've realized that the speed of exposing and transfering the images from the camera at a high rate (>30fps) is causing substantial delay in my UI responsiveness. The processing part is "correctly" threaded to the point that it doesn't affect UI performance (although it may be re-evaluated if I solve this issue) - I mention this because it was done using the older, and supposedly now frowned upon method of subclassing QThread and re-implementing run().

    Where this appears to be different from the examples provided is that rather than creating the QThread objects in some sort of main() function, I create them in the constructor for my QMainWindow object. Then I want to connect a signal from the object I hope to move to the thread, to another object that remains in the current (main) thread. Something like:

    Qt Code:
    1. class WindowApp : public QMainWindow
    2. {
    3. Q_OBJECT
    4.  
    5. WindowApp()
    6. {
    7. myObject = new myObject();
    8. otherObject = new OtherObject();
    9.  
    10. QObject::connect(myObject, SIGNAL(mySignal()), otherObject, SLOT(handleMySignal()));
    11. camera_thread.start();
    12. myObject->moveToThread(&camera_thread);
    13. }
    14.  
    15. private:
    16. QThread camera_thread;
    17. MyObject* myObject;
    18. OtherObject* otherObject;
    19. };
    20.  
    21. class MyObject : public QObject
    22. {
    23. Q_OBJECT
    24.  
    25. MyObject();
    26.  
    27. signals:
    28. void mySignal;
    29. };
    30.  
    31. class OtherObject:: public QObject
    32. {
    33. Q_OBJECT
    34.  
    35. OtherObject();
    36.  
    37. public slots:
    38. void handleMySignal();
    39. };
    To copy to clipboard, switch view to plain text mode 

    The result of running this code is a completely functional application, except that when examining the process ID's of the various functions/slots being called, I can see that (in particular) the slot handlyMySignal() is being executed in the same thread as both the WindowApp constructor and other (not shown here) slots in MyObject.

    After quite a bit of reading, I believe this to be because the QThread camera_thread is owned by WindowApp (which is effectively my "main" thread). The net result is anything happening in handleMySignal() causing the UI to be delayed, due to (I believe) the connection type being modified from queued to direct.

    So my question, finally, is in this scenario how can I define a new thread, move an object to it, AND have that objects slots be executed in the new threads context?? This seems like it shouldn't be that hard, or that uncommon, yet I am stumped.

    Thanks in advance,

    Barry

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: QThread slots not executed in created thread context?

    Quote Originally Posted by bobrien View Post
    The result of running this code is a completely functional application, except that when examining the process ID's of the various functions/slots being called, I can see that (in particular) the slot handlyMySignal() is being executed in the same thread as both the WindowApp constructor and other (not shown here) slots in MyObject.
    That's correct, as you moved only "myObject" to the new thread and not "otherObject". You should move "otherObject" to the new thread if you want its slots to be executed in context of this thread. "myObject" doesn't have to be moved in this case.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Mar 2011
    Posts
    5
    Thanks
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread slots not executed in created thread context?

    Thank you for your quick response. However, as I was concerned that I would, I managed to improperly simplify my code and not show the real problem. Let's try this again, with actual class names that make a bit more sense.

    There are three main classes involved here: CameraThread, Controller, and NozzleApp.

    The idea behind CameraThread is to keep all of the low-level interaction of the camera out of the main UI class. What it *SHOULD* be doing is every time a timer goes off, expose and transfer a new image. All I want it to do, ultimately, is emit a signal that contains a new image (an OpenCV Mat in this case), and perform all of its tasks in a separate thread. This is seen below:
    Qt Code:
    1. class CameraThread : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. CameraThread();
    7.  
    8. private:
    9. Camera* camera;
    10. QTimer imageTimer;
    11.  
    12. private slots:
    13. void getNewImage();
    14.  
    15. signals:
    16. void newImage(Mat);
    17. };
    18.  
    19. CameraThread::CameraThread()
    20. {
    21. camera = new Camera();
    22. QObject::connect(&imageTimer, SIGNAL(timeout()), this, SLOT(getNewImage()));
    23. }
    24.  
    25. void CameraThread::getNewImage()
    26. {
    27. Mat image_out;
    28. camera->captureSingleImage();
    29. image_out = camera->lastImageColor();
    30. emit newImage(image_out);
    31. }
    To copy to clipboard, switch view to plain text mode 

    The Controller class is the interface to some heavy-duty image processing routines. It has its own threaded "pipeline" of processing steps, which works great in its own thread (it was created by sub-classing QThread and reimplementing run()). In this case, its only job is to receive any new images, save some state/data about them, and then pass them off to this processing pipeline.

    Qt Code:
    1. class Controller : public QObject
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. Controller(NozzleApp* parent);
    7.  
    8. private:
    9. NozzleApp* myParent;
    10.  
    11. private slots:
    12. void handleNewImage(Mat newImage);
    13.  
    14. signals:
    15. void new_input_image(Mat);
    16. };
    17.  
    18. Controller::Controller(NozzleApp *parent) : myParent(parent)
    19. {
    20.  
    21. }
    22. void Controller::handleNewImage(Mat newImage)
    23. {
    24. // save some state first
    25. emit new_input_image(newImage);
    26. }
    To copy to clipboard, switch view to plain text mode 

    Finally, NozzleApp is the high-level GUI class. It creates most of the major objects, and sets up some of the communication between objects. Note that the Controller gets passed its parent object (NozzleApp), but CameraThread does not.

    Qt Code:
    1. class NozzleApp : public QMainWindow
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. NozzleApp();
    7.  
    8. private:
    9. Controller* controller;
    10. CameraThread* cam_thread;
    11. QThread camera_thread;
    12. };
    13.  
    14. NozzleApp::NozzleApp()
    15. {
    16. setupUi(this);
    17. controller = new Controller(this);
    18. cam_thread = new CameraThread();
    19. QObject::connect(cam_thread, SIGNAL(newImage(Mat)), controller, SLOT(handleNewImage(Mat)));
    20.  
    21. camera_thread.start();
    22. cam_thread->moveToThread(&camera_thread);
    23. }
    To copy to clipboard, switch view to plain text mode 

    So, back to the original question: What I would hope and expect to see is that the slot getNewImage() in CameraThread (which does the time expensive camera opterations) is executed in a different thread then handleNewImage() in Controller. This is not happening - why?

    Based on everything I've read, and based on your prior response, those two slots are NOT in the same context. I realize that I neglected the QTimer of kicking off getNewImage(), but I figured since the QTimer was supposedly in my new thread, well then its slot would also execute in the new thread (which is not the case).

    Thanks again,
    Barry

  4. #4
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QThread slots not executed in created thread context?

    slots get handled in the thread that the object exists in (by default). I forget how much you can change the behaviour by changing connect(...) arguments.

    It's conceivable that moving the connect for cam_thread after the point where cam_thread has moved thread will change the behaviour of the connection
    Last edited by amleto; 13th September 2011 at 20:37.

  5. #5
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,714
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: QThread slots not executed in created thread context?

    As a side note:
    your naming convention is confusing, and specially in such cases of this sort, can lead to the problem you are having.
    Your CameraThread object is not a thread, so don't call it "thread".
    And having a cam_thread and CameraThread is confusing as well, specially when only one of these objects is a thread.

    Now,
    but I figured since the QTimer was supposedly in my new thread,
    I think this is where the problem is.
    The docs say (for moveToThread()):
    Changes the thread affinity for this object and its children.
    Your QTimer is a member, but no a child.
    Cerate it on the heap with CameraThread as parent, and see if it changes things.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

Similar Threads

  1. Created sub-menus slots won't work
    By thefatladysingsopera in forum Newbie
    Replies: 2
    Last Post: 5th September 2011, 16:29
  2. Replies: 5
    Last Post: 22nd February 2011, 21:21
  3. Receiving slots in QThread's context ?
    By The Storm in forum Qt Programming
    Replies: 10
    Last Post: 14th August 2010, 13:01
  4. QThread slot executed in GUI thread
    By tnyblom in forum Qt Programming
    Replies: 13
    Last Post: 25th May 2010, 07:49
  5. Replies: 3
    Last Post: 5th March 2009, 07:27

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.