Results 1 to 6 of 6

Thread: Quit thread using signal/slot

  1. #1

    Default Quit thread using signal/slot

    Hi, I have a simple problem which I have not been able to solve yet. At least not in the way I think is nicer...

    The setup is a simple worker object that should be run in a different thread. I connect the thread start signal to the worker slot function that should be run and I connect the worker done signal to the thread terminate slot. Then I move the worker to the thread using moveToThread().

    I want to wait for the thread, t, to finish so I call:
    t->start();
    t->wait();

    The work is done, but the program never gets through the wait-condition. So somehow the emitted signal is not triggering the thread terminate slot.

    If I instead call thread()->quit() or thread->exit() instead of emitting the signal everything works.
    If I try and connect to terminate or quit does not matter.

    Here is some sample code, please help me/tell me what the "right" way to solve this problem is and how/why

    Best regards //
    Daniel

    Header:
    Qt Code:
    1. #ifndef MAINWINDOW_H
    2. #define MAINWINDOW_H
    3.  
    4. #include <QMainWindow>
    5. #include <QUrl>
    6. #include <QThread>
    7. #include <QNetworkAccessManager>
    8. #include <QNetworkReply>
    9. #include <QNetworkRequest>
    10. #include <QDebug>
    11.  
    12. namespace Ui {
    13. class MainWindow;
    14. }
    15.  
    16. class DownloadWorker : public QObject
    17. {
    18. Q_OBJECT
    19. public:
    20. explicit DownloadWorker(QObject *parent = 0)
    21. : QObject(parent)
    22. {
    23. qDebug() << "Creating worker";
    24. }
    25. QByteArray* getba() {return &ba;}
    26. private:
    27. QString url;
    28. public slots:
    29. void slotWork();
    30. void slotWorkDone(QNetworkReply *reply);
    31. void prepareDownload(QString url)
    32. {
    33. this->url = url;
    34. }
    35.  
    36. signals:
    37. void workDone();
    38. };
    39.  
    40. class MainWindow : public QMainWindow
    41. {
    42. Q_OBJECT
    43.  
    44. public:
    45. explicit MainWindow(QWidget *parent = 0);
    46. ~MainWindow();
    47.  
    48. private:
    49. Ui::MainWindow *ui;
    50. };
    51.  
    52. #endif // MAINWINDOW_H
    To copy to clipboard, switch view to plain text mode 


    Qt Code:
    1. #include "mainwindow.h"
    2. #include "ui_mainwindow.h"
    3.  
    4. void DownloadWorker::slotWork()
    5. {
    6. QNetworkAccessManager *man = new QNetworkAccessManager(this);
    7. connect(man, SIGNAL(finished(QNetworkReply*)),
    8. this,SLOT(slotWorkDone(QNetworkReply*)));
    9. man->get(QNetworkRequest(QUrl(this->url)));
    10. }
    11.  
    12. void DownloadWorker::slotWorkDone(QNetworkReply *reply)
    13. {
    14. reply->deleteLater();
    15. ba = reply->readAll();
    16. qDebug() << "Download done, exit thread?";
    17. emit workDone();
    18. //thread()->exit(); //things work with this but is it the "right" way to do it?
    19. }
    20.  
    21. MainWindow::MainWindow(QWidget *parent) :
    22. QMainWindow(parent), ui(new Ui::MainWindow)
    23. {
    24. ui->setupUi(this);
    25. QThread *t = new QThread();
    26. DownloadWorker *dw = new DownloadWorker();
    27. dw->prepareDownload("http://www.google.com");
    28. dw->moveToThread(t);
    29. connect(t, SIGNAL(started()),
    30. dw, SLOT(slotWork()));
    31. connect(dw, SIGNAL(workDone()),
    32. t, SLOT(terminate()));
    33. t->start();
    34. qDebug() << "Waiting for thread...";
    35. qDebug() << *dw->getba();
    36. t->wait();
    37. qDebug() << "...done!";
    38. qDebug() << *dw->getba();
    39.  
    40.  
    41. }
    42.  
    43. MainWindow::~MainWindow()
    44. {
    45. delete ui;
    46. }
    To copy to clipboard, switch view to plain text mode 

  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: Quit thread using signal/slot

    You can substitute your whole code with:
    Qt Code:
    1. QNetworkAccessManager manager;
    2. connect(&manager, SIGNAL(finished(QNetworkReply*)), &q, SLOT(quit()));
    3. QNetworkReply *reply = manager.get(QNetworkRequest(QUrl("http://www.google.com")));
    4. q.exec();
    5. QByteArray data = reply->readAll();
    6. reply->deleteLater();
    To copy to clipboard, switch view to plain text mode 
    No threads, no blocked GUI, no synchronisation issues, no problem. You can also add a timer to the whole combination to prevent waiting too long until a failed connection timeouts.
    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

    Default Re: Quit thread using signal/slot

    Hi and thank you for your quick reply. The solution works... but if you are downloading large files or over slow connections the application will wait until the event loop is finished which is not optimal.

    I reckon the sample I provided may not be the best, but it is somewhat in the direction I am striving.
    So still my question is yet to be answered: Why is not the terminate slot called from the emitted signal? What can be changed so that the sample I wrote works? Is the best solution to manually call quit/exit on the thread from within the worker?

    In the complete application there will be one main thread which spawns two(or more) other threads. From one of these threads workers will be created and it is this thread that I would like to wait until the worker-thread is done.

  4. #4
    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: Quit thread using signal/slot

    Quote Originally Posted by mounte View Post
    Hi and thank you for your quick reply. The solution works... but if you are downloading large files or over slow connections the application will wait until the event loop is finished which is not optimal.
    Correct me if I'm wrong but the same will happen with your code:
    Qt Code:
    1. t.start();
    2. t.wait(); // waits until "t" dies
    To copy to clipboard, switch view to plain text mode 

    I reckon the sample I provided may not be the best, but it is somewhat in the direction I am striving.
    Trust me, it is not.

    So still my question is yet to be answered: Why is not the terminate slot called from the emitted signal?
    Because the (main) thread that is to call the slot is waiting for your thread to finish which will never happen because quitting the slot requires the thead owning the thread controller to be alive which will never happen because you blocked it until the thread dies. Do you see the infinite loop?

    What can be changed so that the sample I wrote works?
    The only viable solution I see is to not use a thread because you don't need it for anything.

    I strongly recommend to read this article: [wiki]Keeping the GUI Responsive[/wiki].

    If you don't want the application to wait then simply remove the event queue from my code and use signals and slots. Threads don't solve anything here, especially if you block the calling thread.
    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.


  5. #5

    Default Re: Quit thread using signal/slot

    Thank you for your answer.
    It now makes sense, my "solution" (that really would not have worked very well or not at all) would have been really awful I realize.

    Quote Originally Posted by wysota View Post
    Correct me if I'm wrong but the same will happen with your code:
    Qt Code:
    1. t.start();
    2. t.wait(); // waits until "t" dies
    To copy to clipboard, switch view to plain text mode 
    Yes this would block, the idea was that the main thread and my other worker thread would still be alive. The blocking would be of just one thread.
    And my own stupidity lead me in the wrong direction instead of keeping it simple.

    Thank you very much for your help and taking your time with me, your recommended link was also appreciated.

  6. #6
    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: Quit thread using signal/slot

    A general rule is that if you block one thing to do another in a thread then you don't need the thread. Another is that network operations in Qt don't benefit from using threads.
    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.


  7. The following user says thank you to wysota for this useful post:

    bob2oneil (4th April 2011)

Similar Threads

  1. QMenu connect to quit slot
    By Hostel in forum Newbie
    Replies: 4
    Last Post: 18th October 2010, 21:51
  2. QThread Signal Not Received By Main Thread Slot
    By EF2008 in forum Qt Programming
    Replies: 7
    Last Post: 4th June 2010, 08:06
  3. Replies: 9
    Last Post: 28th November 2009, 20:31
  4. Replies: 16
    Last Post: 28th October 2008, 22:00
  5. Replies: 1
    Last Post: 11th September 2008, 20:45

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.