Results 1 to 10 of 10

Thread: Restart a QThread

  1. #1
    Join Date
    Jun 2016
    Posts
    9
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Restart a QThread

    Hi

    I've some troubles with threading. In my application I've separated the GUI and a streaming/processing part into 2 threads. The streaming thread is created like the example in the QThread Class documentation. For a "single shot" that works great (starting and stopping the streaming thread). But if I re-click the streaming button the application crashes. There is no difference if I call the destructor for my background-worker class and recreate a complete new instance, or if I only re-call the thread start function.

    Where is my problem?

    Here are the specific parts:
    Qt Code:
    1. MainWindow::MainWindow(QWidget *parent) :
    2. QMainWindow(parent),
    3. ui(new Ui::MainWindow)
    4. {
    5. backgroundWorker = new workerThread;
    6. //Setup callback for cleanup when it finishes
    7. connect(backgroundWorker, SIGNAL(finished()), backgroundWorker, SLOT(deleteLater()));
    8. connect(backgroundWorker, SIGNAL(FrameReady()), this, SLOT(update_detection_lb()));
    9.  
    10. connect(ui->StartStopStreaming_pb, SIGNAL(clicked()), this, SLOT(Streaming()));
    11.  
    12. // Set gui labels
    13. ui->Gain_lb->setText(QString("%1 dB").arg(backgroundWorker->gain));
    14. ui->fc_lb->setText(QString("%1 MHz").arg(backgroundWorker->freq / 1e6));
    15. ui->adr_lb->setText(QString::fromStdString(backgroundWorker->addr));
    16. }
    17.  
    18. // Streaming button
    19. void MainWindow::Streaming()
    20. {
    21. if(ui->StartStopStreaming_pb->text() == "Start streaming")
    22. {
    23. ui->StartStopStreaming_pb->setText("Stop streaming");
    24.  
    25. std::cout << "Start streaming in background thread" << std::endl;
    26.  
    27. if(backgroundWorker)
    28. {
    29. backgroundWorker->m_abort = false;
    30. backgroundWorker->start(QThread::HighestPriority);
    31. }
    32. }
    33. else{
    34. ui->StartStopStreaming_pb->setText("Start streaming");
    35.  
    36. std::cout << "Stop streaming and terminate background thread" << std::endl;
    37.  
    38. backgroundWorker->m_abort = true;
    39. if(!backgroundWorker->wait(5000))
    40. {
    41. std::cout << "Thread deadlock detected, bad things may happen!" << std::endl;
    42.  
    43. backgroundWorker->terminate();
    44. backgroundWorker->wait();
    45. }
    46. }
    47. }
    48.  
    49. void workerThread::run()
    50. {
    51. std::cout << "Thread running" << std::endl;
    52.  
    53. while(m_abort == false)
    54. {
    55. // Do some streaming stuff
    56. }
    57.  
    58. std::cout << "Thread terminated" << std::endl;
    59. emit finished();
    60. }
    To copy to clipboard, switch view to plain text mode 

    Best regards,
    P51D

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Restart a QThread

    A couple of things:

    1) access to workerThread::m_abort is not properly synchronized between the two threads.
    2) backgroundWorker gets deleted when it finishes but there doesn't seem to be any code to reset the variable, yet there is an if (backgroundWorker)
    3) QThread::terminate() is a bad thing

    Cheers,
    _

  3. #3
    Join Date
    Jun 2016
    Posts
    9
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: Restart a QThread

    Quote Originally Posted by anda_skoa View Post
    1) access to workerThread::m_abort is not properly synchronized between the two threads.
    I know the "proper" way would be using mutex or signal/slots. But in this case I'm only reading the variable from one thread and writing it from the other...

    2) backgroundWorker gets deleted when it finishes but there doesn't seem to be any code to reset the variable, yet there is an if (backgroundWorker)
    I don't know what you mean. Can you explain it in other words?

    3) QThread::terminate() is a bad thing
    I know, but this is only an "emergency" solution, if the thread blocks about 5 sec.

    Best regards

  4. #4
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Restart a QThread

    Quote Originally Posted by P51D View Post
    I know the "proper" way would be using mutex or signal/slots. But in this case I'm only reading the variable from one thread and writing it from the other...
    Read/write from different threads is what needs to be synchronized.
    Only reading from two threads is OK without protection.

    But for this case you could also have a look at QThread::requestInterruption() which already implements that.

    Quote Originally Posted by P51D View Post
    I don't know what you mean. Can you explain it in other words?
    You have connected the thread's finished() signal to its deleteLater() slot, so the thread is deleted when the thread ends.
    But the pointer variable is not reset anywhere I can see.

    Quote Originally Posted by P51D View Post
    I know, but this is only an "emergency" solution, if the thread blocks about 5 sec.
    Why do you even need to wait for the thread to end?
    It gets deleted once it finishes, no matter if it does that after 1 millisecond or after 10 seconds.

    Cheers,
    _

  5. #5
    Join Date
    Jun 2016
    Posts
    9
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: Restart a QThread

    Some updates:

    I managed to synchronize the stop call with requenstInterruption. But the other thing with restarting the thread wont work. It doesn't matter if I delete the object like this and try to create a new instance:

    Qt Code:
    1. delete backgroundWorker;
    2. workerThread* backgroundWorker = new workerThread;
    To copy to clipboard, switch view to plain text mode 

    I'm a bit confused.

  6. #6
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Restart a QThread

    If that is your actual code then you have just created a local variable that shadows the member variable with the same name.

    Cheers,
    _

  7. #7
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Restart a QThread

    Once you fix the shadow variable issue that @anda_skoa pointed out, you'll need to redo your connects after you've created the new workerThread, it is a new instance, etc.
    I write the best type of code possible, code that I want to write, not code that someone tells me to write!

  8. #8
    Join Date
    Jun 2016
    Posts
    9
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: Restart a QThread

    Sorry, my fault. Off course it is not a local member...

    For better understanding I have here the code (sry, this should be the first thing when asking for help).

    Main window
    Qt Code:
    1. class MainWindow : public QMainWindow
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. explicit MainWindow(QWidget *parent = 0);
    7. ~MainWindow();
    8.  
    9. public slots:
    10. void update_detection_lb();
    11. void Streaming();
    12.  
    13. private:
    14. Ui::MainWindow *ui;
    15.  
    16. // UHD backround worker thread
    17. workerThread *backgroundWorker;
    18. };
    19.  
    20.  
    21.  
    22.  
    23. MainWindow::MainWindow(QWidget *parent) :
    24. QMainWindow(parent),
    25. ui(new Ui::MainWindow)
    26. {
    27. backgroundWorker = NULL;
    28. backgroundWorker = new workerThread;
    29. //Setup callback for cleanup when it finishes
    30. connect(backgroundWorker, SIGNAL(finished()), backgroundWorker, SLOT(deleteLater()));
    31.  
    32. // Setup signal slot connections
    33. connect(ui->StartStopStreaming_pb, SIGNAL(clicked()), this, SLOT(Streaming()));
    34. connect(backgroundWorker, SIGNAL(FrameReady()), this, SLOT(update_detection_lb()));
    35.  
    36. }
    37.  
    38.  
    39. void MainWindow::Streaming()
    40. {
    41. if(ui->StartStopStreaming_pb->text() == "Start streaming")
    42. {
    43. ui->StartStopStreaming_pb->setText("Stop streaming");
    44.  
    45. if(backgroundWorker == NULL)
    46. {
    47. backgroundWorker = new workerThread;
    48. connect(backgroundWorker, SIGNAL(finished()), backgroundWorker, SLOT(deleteLater()));
    49. connect(backgroundWorker, SIGNAL(FrameReady()), this, SLOT(update_detection_lb()));
    50. }
    51. backgroundWorker->start(QThread::HighestPriority);
    52.  
    53. std::cout << "Start streaming in background thread" << std::endl;
    54. }
    55. else{
    56. ui->StartStopStreaming_pb->setText("Start streaming");
    57.  
    58. backgroundWorker->requestInterruption();
    59. if(!backgroundWorker->wait(5000))
    60. {
    61. std::cout << boost::format("Thread deadlock detected, bad things may happen!") << std::endl;
    62. backgroundWorker->quit();
    63. backgroundWorker->wait();
    64. }
    65. std::cout << "Stop streaming and terminate background thread" << std::endl;
    66. delete backgroundWorker;
    67. }
    68. }
    To copy to clipboard, switch view to plain text mode 

    Worker thread
    Qt Code:
    1. class workerThread : public QThread
    2. {
    3. Q_OBJECT
    4.  
    5. public:
    6. workerThread();
    7. ~workerThread();
    8.  
    9. protected:
    10. void run();
    11.  
    12. signals:
    13. void finished();
    14. void FrameReady();
    15.  
    16. private:
    17.  
    18. // UHD member
    19. uhd::usrp::multi_usrp::sptr usrp;
    20. uhd::rx_streamer::sptr rx_stream;
    21. };
    22.  
    23.  
    24. workerThread::workerThread()
    25. {
    26. std::cout << "Thread created" << std::endl;
    27. }
    28.  
    29. workerThread::~workerThread()
    30. {
    31.  
    32. }
    33.  
    34.  
    35. void workerThread::run()
    36. {
    37. std::cout << "Thread running" << std::endl;
    38.  
    39. while(!this->isInterruptionRequested())
    40. {
    41. // Do streaming stuff
    42. emit FrameReady();
    43. }
    44.  
    45. std::cout << "Thread terminated" << std::endl;
    46. emit finished();
    47. }
    To copy to clipboard, switch view to plain text mode 

    The Problem is still the same. During the first start/stop all works fine. But when I try to restart the thread, I don't come into the if(backgroundWorker == NULL) and the program hangs at the backgroundWorker->start line.

  9. #9
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Restart a QThread

    Perhaps set background worker to null after you delete it in line 66?
    I write the best type of code possible, code that I want to write, not code that someone tells me to write!

  10. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Restart a QThread

    Quote Originally Posted by P51D View Post
    The Problem is still the same. During the first start/stop all works fine. But when I try to restart the thread, I don't come into the if(backgroundWorker == NULL) and the program hangs at the backgroundWorker->start line.
    You are artifically creating a different situation for startup vs. runtime by creating and connecting a thread in the constructor.

    As far as I can tell the only thing the slot would need to do is to disconnect() from the old thread if it exists and create and start the new thread.
    Since the thread is deleted via deleteLater(), you will need a QPointer for "backgroundWorker" so it can track if the object still exists.
    Qt Code:
    1. void MainWindow::Streaming()
    2. {
    3. if(ui->StartStopStreaming_pb->text() == "Start streaming")
    4. {
    5. ui->StartStopStreaming_pb->setText("Stop streaming");
    6.  
    7. backgroundWorker = new workerThread;
    8. connect(backgroundWorker, SIGNAL(finished()), backgroundWorker, SLOT(deleteLater()));
    9. connect(backgroundWorker, SIGNAL(FrameReady()), this, SLOT(update_detection_lb()));
    10. backgroundWorker->start(QThread::HighestPriority);
    11.  
    12. std::cout << "Start streaming in background thread" << std::endl;
    13. }
    14. else{
    15. ui->StartStopStreaming_pb->setText("Start streaming");
    16.  
    17. if(backgroundWorker != 0)
    18. {
    19. disconnect(backgroundWorker, SIGNAL(FrameReady()), this, SLOT(update_detection_lb()));
    20. backgroundWorker->requestInterruption();
    21. }
    22. }
    23. }
    To copy to clipboard, switch view to plain text mode 


    Alternatively you could look into keeping the same thread object and just making it "pause/resume".

    Cheer,
    _

Similar Threads

  1. Restart Qt Application
    By sh_erfan in forum Newbie
    Replies: 11
    Last Post: 18th August 2015, 12:17
  2. How to restart an application
    By Naami in forum Qt Programming
    Replies: 11
    Last Post: 21st January 2015, 15:47
  3. Replies: 1
    Last Post: 4th October 2012, 14:49
  4. Restart Application
    By d4rc in forum Newbie
    Replies: 8
    Last Post: 13th May 2010, 14:24
  5. how to restart the MainWindow?
    By d@nyal in forum Newbie
    Replies: 2
    Last Post: 3rd May 2010, 03:51

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.