artyom.stv
artyom.stv

Reputation: 2164

Help me understand the QThread usage

I have the MainWindow w windows and TestThread testThread as a member of w. I know it i simple, but I cannot run the testThread.foo() method in testThread thread (not in window thread). In another words: I don't understand the QThread behavior.

Please help correct the next test application. There is a QProgressBar *MainWindow::ui::progressBar and QPushButton *MainWindow::ui::startButton (write simply). I want to start (by startButton click) TestThread::foo(int* progress) which will increment int progress each second.

MainWindow:

MainWindow::MainWindow(QWidget *parent) : // ...
{
    // ...

    ui->progressBar->setRange(0, 5);
    progress = 0; // int MainWindow::progress

    this->connect(ui->startButton, SIGNAL(clicked()), SLOT(startFoo()));

    connect(this, SIGNAL(startFooSignal(int*)), &testThread, SLOT(foo(int*)));
        // TestThread MainWindow::testThread

    testThread.start();
}

// ...

void MainWindow::timerEvent(QTimerEvent *event)
{
    ui->progressBar->setValue(progress);
}

void MainWindow::startFoo() // this is a MainWindow SLOT
{
    startTimer(100);
    emit startFooSignal(&progress);
        // startFooSignal(int*) is a MainWindows SIGNAL
}

TestThread:

void TestThread::foo(int *progress) // this is a TestThread SLOT
{
    for (unsigned i = 0; i < 5; ++i) {
        sleep(1);
        ++*progress; // increment MainWindow::progress
    }
}

I know, this is simple. I am doing something wrong :)

P.S. I want to run the simpliest (as possible) example to understand the QThread behavior.

Thanks!

Upvotes: 0

Views: 1365

Answers (3)

Macke
Macke

Reputation: 25690

The critical issue is to have the object containing the foo()-function be owned by that thread, so that slot calls are dispatched from the right thread's event-loop.

(Note that there's no need to actually have foo() on the TestThread object. You can use separate objects for QThread and WhatEver::foo() function. It might be easier too, I'm not sure..)

IIUC, this is what you have to do:

  • Use QObject::moveToThread() to assign the object containing the foo-function to TestThread (that means that Qt::AutoConenction (the default) signal/slots calls will run correctly across thread, being dispatched from each thread's own event loop).

By having the object "owned" by the right thread, slots calls will be scheduled on that thread's event loop, rather than executed directly.

Hope it helps. :)

Upvotes: 2

zkunov
zkunov

Reputation: 3412

One alternative solution: If you just want to run a function in another thread, and don't insist using QThread, you should check out the QT Concurrent Namespace.

The following example will run the function foo() in separate thread and will not block on the line where calling the function. Of course there are mechanisms to understand when a function ends, to get a result, to wait for it, to control execution.

void foo(int &progress) {...}

int progress;
QtConcurrent::run(foo, progress);

Hope this helps

Upvotes: 2

sashoalm
sashoalm

Reputation: 79665

See QThread::start and QThread::run.

Upvotes: 1

Related Questions