I am getting a run-time message
QObject: Cannot create children for a parent that is in a different thread.
when starting a QProcess
in a std::thread
. The program runs, but I feel that this message will be trouble, eventually.
I saw this one and this other answers (as well as some in python), which I did not see how to apply to my code.
I am using QtCreator, Qt 6.5 LTS and gcc 11.2.0 in Win10. A minimal working example is below. You will have to create an empty GUI window with QPushButton pushButton
. The class definition is:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void clicked(bool);
private:
Ui::MainWindow *ui;
void launchNotepad();
std::thread th;
QProcess process;
};
And the implementation is:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(clicked(bool)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::clicked(bool)
{
th = std::thread{&MainWindow::launchNotepad,this};
th.detach();
}
void MainWindow::launchNotepad()
{
process.start("notepad");
}
When I click on the button, notepad indeed appears and all looks well. But the Application output console in QtCreator gives me the message "Cannot create children...". For reasons beyond this question, I do want to work with std::thread
.
My questions:
What is the trouble that I am sure eventually I'll have because of this message ?
How to get rid of it, while keeping using std::thread
?
A QProcess
is also a QObject
, and each QObject
has an associated thread. By default the thread of the QObject
is the one that created it. In this case, since it's a member of your own QMainWindow
-based class, and will have been created when your main window has been created, it will by default have the same thread as your main window, which is not the thread you are trying to use QProcess
from.
Since QProcess
internally creates other QObject
s, those objects will have been created in the thread that called process.start()
. But that is not the thread that QProcess
belongs to. And since QObject
parent-child relationships can only work for objects in the same thread, you'll get this debug message from Qt, because QProcess
can't properly create the desired sub-objects it wants to create.
You have three options here to solve this (in increasing order of simplicity and usefulness):
Move the QProcess
to the thread that is using it with moveToThread()
. Unfortunately, to be 100% conforming to Qt's API, you must call that method from the thread QProcess
currently resides in, which would mean a lot of complicated synchronization logic to properly do that, because you'd need to first create the thread, then get the QThread*
id of the thusly created thread, then call moveToThread()
from the main thread, and then indicate to the thread that it can now use QProcess
. Plus you'd need to think about what you want to happen to the process
object once the sub-thread exits.
Actually create the QProcess
in the thread that you want to use the start()
method in. In that case you can simply do something like:
void MainWindow::launchNotepad()
{
QProcess process;
process.start("notepad");
}
Unfortunately that will also cause QProcess
object to cease existing at the end of the scope of that function. You could of course return that QProcess to the main thread by allocating it on the heap and with some synchronization logic, but that also gets complicated quite fast.
Plus, again, you'd need to think about what you'd want to do with the thusly created process when your sub-thread exits.
But this is all way too complicated, because:
QProcess
from the main thread. There is typically no reason to use it from a separate thread, QProcess
supports signals and slots, and is therefore easily used asynchronously anyway. There is absolutely no reason to use a separate thread for this.