1

I need to have a computationally intensive function run in a different thread so that the GUI doesn't freeze or turn grey when it's running.

I followed this example: https://stackoverflow.com/a/16501374/2904614

But the GUI still freezes and turns grey.

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->textBrowser->setFont(QFont("Monospace",11));
    ui->textBrowser->setLineWrapMode(QTextEdit::NoWrap);

    updater->moveToThread(thread);
    connect(updater,SIGNAL(req()), this, SLOT(getCheckSum()));
    connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater()));
    thread->start();
}

When the user clicks the designated button. Since there may be a lot of files in one directory, the GUI will freeze as QDirIterator goes through all of them. I'm hoping to add a progress bar, that will show the user the program is still functioning.

void MainWindow::on_pushButton_clicked()
{
    updater->getHash();
    //getCheckSum();
}

EDIT I would like to have the function MainWindow::getCheckSum() run in a different thread than the GUI. How will I implement this?

Github: https://github.com/Jyang772/PenguSniff

Community
  • 1
  • 1
Quaxton Hale
  • 2,460
  • 5
  • 40
  • 71
  • Where do you new updater? Does it have a parent? Do you start the thread? – Nejat May 25 '14 at 17:17
  • I do that in the class declaration for MainWindow. Yes, I start the thread after connecting the slots/signals. updater doesn't have a parent, since I can't use `moveToThread` if it does. – Quaxton Hale May 25 '14 at 17:34
  • Where your for loop is executed? It is unclear from you question and probably runs in GUI thread. I propose to put it in getHash() before emit req(). – Basilevs May 26 '14 at 01:30
  • @Basilevs I did put it in `getHash()`. Right now I just replaced it with an infinite while loop to test if GUI is responsive. – Quaxton Hale May 26 '14 at 01:42
  • @MicroPenguin, please update the question in a way, that it would become clear where loop is executed. It is still unclear what is "the function I want to call in a different thread". Also, take a look at [SSCCE](http://www.sscce.org/) – Basilevs May 26 '14 at 01:48

3 Answers3

1

Given you only need to run one function i would recommend QtConcurrent. Extract form the docs:

Running a Function in a Separate Thread

To run a function in another thread, use QtConcurrent::run():

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);

This will run aFunction in a separate thread obtained from the default QThreadPool. You can use the QFuture and QFutureWatcher classes to monitor the status of the function.

Sebastian Lange
  • 3,879
  • 1
  • 19
  • 38
  • By the way, there is no other framework having as cool classes as QFuture and QFutureWatcher. Sounds like easy implementation of a time machine – Sebastian Lange May 26 '14 at 05:39
  • Thanks! However, I have some other functions that I would like to call if the user presses different buttons. I need to clear the textbrowser of any text, however it seems as though the thread starts before the textbrowser clears itself. – Quaxton Hale May 26 '14 at 06:36
  • Clearing a text browser is not intended to be run in separated thread. As by your description only the computing-function has to be run in a separate thread, therefor using QtConcurrent is eligible. – Sebastian Lange May 26 '14 at 06:40
  • I realized that I had a global variable with the same name as a local variable in the function. This was why textbrowser was never being modified when I wanted it to. Thank you for suggesting `QtConcurrent` – Quaxton Hale May 26 '14 at 06:54
0

The problem is that you are calling the function of a class in another thread directly:

updater->getHash();

It causes undefined behavior in your application and makes it crash. The correct way is to emit a signal from your MainWindow which is connected to the getHash() slot in updater:

connect(this,SIGNAL(getHash()), updater, SLOT(getHash()));


void MainWindow::on_pushButton_clicked()
{
    emit getHash();
}

This will result in a queued connection and runs the slot in the updater thread.

Nejat
  • 31,784
  • 12
  • 106
  • 138
  • 1
    The application doesn't 'crash', it just turns grey when iterating through directories. When it's done, the GUI becomes responsive again. I tried this method, and still the same result. How do I know for sure it's being processed on a different thread? – Quaxton Hale May 25 '14 at 21:13
0

You call your getHash() computational function (it is computational as per your comment) in GUI thread. Bind it to clicked signal, then it will be invoked in object's thread.

connect(button, SIGNAL(clicked()), this, SLOT(getHash()));
Basilevs
  • 22,440
  • 15
  • 57
  • 102