Search code examples
c++qtqthread

QT QThread::isrunning freeze program on Pi


I'm testing a programm on my PI.When running it on the host pc no error is shown, instead , running it on pi (CM3) it freezes.

I'm trying to use multithreading.

From the main thread, in the constructor an QThread is started, then when I click on the button to open a new form the GUI freezes. In the button slot I need to check if the serial_works thread has been started in the constructor has finished before opening a new form, so I added a QThread::isRunning() check;

Main_Form::Main_Form(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Main_Form)
{
    ui->setupUi(this);
    this->move(0,0);
    this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);         
    connect(ui->btn,SIGNAL(clicked(bool)),this,SLOT(open_form()));
    *serial_works = new SerialWorks();
    serial_works->start();
}

void Main_form::open_form(){
std::cout<<"open form slot"<<std::endl;
int i = 0;
while(serial_works->isRunning()){
    std::cout<<"WHILE"<<std::endl;
    QThread::msleep(100);
    i++;
    if(i > 10){
        serial_works->terminate();
    }
Next_form *frm = new Next_form();
this.close();
frm->show();
}

the run method in the Serial_works class is

void Serial_works::run() {
   my_function();
   this->terminate();
   this->wait();
}

void Serial_works::my_function(){
  ....stuff on serial
  std::cout<<"serial works finished"<<std::endl;
}

on the output i get

 //serial works finished
 //open_slot_form

no WHILE is printed out on the console,thus the program get stuck on the while check

serial_works->isRunning()

Where is the problem? On the the host pc, the new form opens as expected.


Solution

  • You are trying to use QThread without understanding what is this object doing. What you want to do is asynchronous execution : Do some work and when you are done let me know.

    Edit : What is Happening :

    • Client : main thread executes open_form before the worker executes run
    • Rasberry Pi : worker executes run before main thread executes open_form

    On PI

    1. serial_works->start() launch worker, which execute first, and complete my_function.
    2. worker call this->terminate() and is now officially dead. terminate is a brutal way of stopping a QThread..I cannot even speculate whether wait() is called.
    3. The main thread execute open_form, and the worker is already non-runnable. So the loop is not executed and Next_form is never going to be shown.

    Error 1 :

    Main_form::open_form()
    

    is executing in the gui thread, and you are sleeping on a event. This is always incorrect. You GUI will freeze for the amout of time you are sleeping. Use signals and slots or events.

    Error 2 :

    Serial_works is likely a subclass of Qthread. You are confusing a thread of execution with the object managing that thread. You should not subclass QThread.

       this->terminate();
       this->wait();
    

    The worker thread is executing that code. You are killing yourself then waiting on your death. So depending on the implementation you may wait forever , crash, etc....

    What you need to do : Use QFuture and QFutureWatcher.

    //inside Main_Form
    QFutureWatcher<ReturnValueType> watcher;
    
    void Main_form::open_form(){
        // Instantiate the objects and connect to the finished signal.
        connect(&this->watcher, SIGNAL(finished()), &this, SLOT(SignalWorkFinished()));
    
        // Start the computation.
        QFuture<ReturnValueType> future = QtConcurrent::run(stuffOnSerialFunction);
        this->watcher.setFuture(future);
    }
    
    // now handle work finish
    void SignalWorkFinished()
    {
       QFuture<ReturnValueType> future = watcher.future();
       //do whatever you like
    }