0

this is the run method of a subclass of QThread:

void crono::Controller::run() {

    //initialise timer
    int *i = & this->model->seconds_elapsed;

    for (*i = 0; *i < this->model->seconds_total; (*i)++) {

    //calculate current seconds/minutes/hours elapsed starting  from seconds_elapsed (*i)
    this->model->tick(); 

    //should display in the form the time elapsed
    this->vista->showTime(); 
    sleep(1000);


    }

    Beep(1000, 500); //beep when all is over

}

the controller updates the model values.

The QT form is opened on start, I guess in the main application thread.

The issue is that despise on debug *i=0 and seconds_total = X > 0, the loop is executed only one time, after the first time the debug halt (it does not end), the forms pops up but nothing happens.

The only thing I can guess of, is that the Controller Thread lose its priority and never gains the cpu again.

How can avoid this?

EDIT I am trying using QTimer, with bad luck.

i declared update as a public slot, and then implemented like this:

void crono::Controller::update() { 

    this->modello->tick();
    this->vista->showTime();

    //eventually stop at some point (pointer to timer and timer->stop()? 
    //...
    //Beep(1000, 500);
}  

And I inserted the QTimer in the controller (thread) object instead of the loop cycle:

void crono::Controller::run() {

    //inizializzo timer
    int *i = & this->modello->secondi_trascorsi;

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()),this, SLOT(update()));
    timer->start(1000);


}

I do not know why, but the update() method is never called, instead of being called an infinite number of times. Why?

3
  • No I don't think this can be the problem. Debug or add some debug logging to check if you reach the sleep clause. Maybe one of the other methods is causing infinite loop? Commented Feb 6, 2013 at 9:31
  • "//should display in the form the time elapsed" - are you sure, that you don't access GUI directly from thread, but doing it via signal/slots only ? Commented Feb 6, 2013 at 9:59
  • 2
    I strongly suggest keeping the QThread and the implementation separate from each other, i.e. don't subclass QThread (Read Zaiborg's link). If you however really reimplement QThread::run(), you need to call exec() at the end of the run() method, otherwise any events (including signals) will never be processed by the thread. Commented Feb 6, 2013 at 12:20

4 Answers 4

6

A common confusion is that QThread runs in its own separate thread. This is not the case; instead, QThread starts an event loop in a child thread that it controls. QThread could easily be called QThreadManager.

In short, don't subclass QThread, as the functionality you're creating resides in the main thread (not the thread that QThread handles). Create a QObject subclass with a slot connected to the started() signal. Then use moveToThread() and call run() on your QThread instance.

Also, you can't directly call main thread functions from a child thread. You'll need a queued connection signal to an object in the main thread to show the dialog box.

Sign up to request clarification or add additional context in comments.

Comments

3

As Tim Meyer pointed out in his comment, you need to call QThread:exec() at the end of your QThread::run() implementation, this in order to start the thread's event loop, which is needed in order for the Signal/Slot mechanism to work.

However, it seems like you're doing it wrong.

2 Comments

I am doing it wrong because of a blog post hinted to inherit QThread /meh
I think even the Qt docs hinted that for a while. Very good example on how it is done: qt-project.org/doc/qt-4.8/QThread.html#details
2

First of all, QThread is not supposed to be inherited for nearly any reason.

Threading usually will be done like described there: http://qt-project.org/doc/qt-4.8/QThread.html#details

If you just need the thread to count some time and do stuff after a period of time, maybe you can use QTimer instead and connect the QTimer::timeout() signal to your slot to display the elapsed time.

Comments

1

I'm sure your loop should look like this:

//initialize timer
int elapsed = this->model->seconds_elapsed;

for (int i = 0; i < elapsed; i++) 

I see no need to use a pointer. Keep it simple.

If this still doesn't work, you're doing something else wrong, and it's not obvious from your code.

Also thread signalling isn't done using sleep. You should look into thread events like semaphore's or condition variables for thread signalling purposes.

If you want to update values periodically, why not use a QTimer?

sleep has only very few valid uses, and I'm sure that you're solving a problem that doesn't require sleep.

1 Comment

a pointer is needed in order to update the status of the model at each cycle

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.