1

As a learning example I am trying to test std::thread with Qt instead of QThreads. The application is a very basic QMainWindow application,see code bellow:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QString>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    [[ noreturn ]] void operator()();

private:
    Ui::MainWindow *ui;
    QString mm;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

[[ noreturn ]] void MainWindow::operator()()
{
    qDebug()<< "thread runing";
    int i =0;
    while (1)
    {
        i++;
    }
}

main.cpp

#include <thread>
#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow mainWindow;
    mainWindow.show();
    std::thread t(&mainWindow);
    t.detach();
    return app.exec();
}

This code does not compile and produces the error:

In file included from /home/faroub/Documents/development-projects/projects-c++/Qt-CMake-GUI/HelloWorld/main.cpp:1:0:
/usr/include/c++/7/thread: In instantiation of ‘struct std::thread::_Invoker<std::tuple<MainWindow*> >’:
/usr/include/c++/7/thread:127:22:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = MainWindow*; _Args = {}]’
/home/faroub/Documents/development-projects/projects-c++/Qt-CMake-GUI/HelloWorld/main.cpp:10:30:   required from here
/usr/include/c++/7/thread:240:2: error: no matching function for call to ‘std::thread::_Invoker<std::tuple<MainWindow*> >::_M_invoke(std::thread::_Invoker<std::tuple<MainWindow*> >::_Indices)’
  operator()()
  ^~~~~~~~

Any ideas why it does not work ? Do I have to QThreads with Qt? is it related to the QObject? thank you in advance.

faroub
  • 23
  • 4
  • What on earth you expect from std::thread? It's argument must a callable. Also Qt framework and standard threading component are inherently incompatible, so yes, you should use qconcurrent\qthread\qthreadpool – Swift - Friday Pie Mar 29 '20 at 18:43
  • 1
    Does this answer your question? [Start thread with member function](https://stackoverflow.com/questions/10673585/start-thread-with-member-function) – Swift - Friday Pie Mar 29 '20 at 18:48
  • @Swift-FridayPie There's nothing inherently incompatible with Qt and `std::thread`, if you don't plan to run Qt event loop in the thread. – hyde Mar 29 '20 at 19:59
  • 2
    @faroub Note that most of Qt is not thread safe, and in particular GUI stuff must run in the main thread. So be very very careful what you do in that member function, which is executed in another thread. Having it in the same class, with access to same private class data, is asking for trouble (making a mistake when accessing it from multiple threads). – hyde Mar 29 '20 at 20:03
  • 1
    Be note that GUI elements cannot be used from non-main threads at all. You can interact with your own variables, but not with widgets. – Vladimir Bershov Mar 29 '20 at 20:23
  • 1
    Read the answer about Qt threads and GUI https://stackoverflow.com/a/60755238/4149835 – Vladimir Bershov Mar 29 '20 at 20:31
  • @hyde creating `QObject` within standard thread and then trying to use its event facilities somewhere else leads to UB too. All `QObject`s must have affinity to main thread or to appropriate `QThread`, so its much worse limitation than Vladimir said. In fact even "side" subsystems like `QFile` \\`QFileSystem` are using event system inside of them so you can't use them either. Latter can lead to corrupted file if main thread (containg QApplication) was terminated before file was flushed and closed. – Swift - Friday Pie Mar 30 '20 at 11:11
  • @Swift-FridayPie That does not make Qt and std:: thread incompatible. If they were, many 3rd party libraries would not work with Qt, which would be kinda bad... – hyde Mar 30 '20 at 13:43

1 Answers1

1

Instead of passing a pointer to your thread constructor, pass it a std::reference_wrapper like this:

std::thread t(std::ref(mainWindow));

That wrapper comes from the <functional> header.

You were right to try to pass a reference (by address), because if not then a copy of the MainWindow would have been created (not what you want). But there is no valid constructor in std::thread that would take a pointer to a functor and call it.

rems4e
  • 3,112
  • 1
  • 17
  • 24