QObject: Cannot create children for a parent that is in a different thread & QProcess [duplicate] - qt

I am using Qt 4.6.0 (32 bit) under Windows 7 Ultimate. Consider the following QThread:
Interface
class ResultThread : public QThread
{
Q_OBJECT
QString _post_data;
QNetworkAccessManager _net_acc_mgr;
signals:
void onFinished(QNetworkReply* net_reply);
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
ResultThread();
void run();
void setPostData(const QString& post_data);
};
Implementation
ResultThread::ResultThread() : _net_acc_mgr(this)
{
connect(&_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void ResultThread::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void ResultThread::setPostData(const QString& post_data)
{
_post_data = post_data;
}
void ResultThread::run()
{
_net_acc_mgr.post(QNetworkRequest(QUrl("http://[omitted]")),
QByteArray(_post_data.toStdString().c_str()));
}
Whenever _net_acc_mgr.post() is executed in ResultThread::run(), I got the following Application Output in Qt Creator:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x22fe58), parent's thread is QThread(0x9284190), current thread is ResultThread(0x22fe48)
What does this mean? How to solve it?

The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.
This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.
Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.
The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.

I received this error message when I forgot to set the QNetworkRequestManager's parent.
nam = new QNetworkAccessManager(this);

Related

Qt: How to avoid deadlock when multiple queued signals invoke same slot

In following code I meet deadlock in someOperation:
class A : public QObject {
Q_OBJECT
public:
explicit A(QObject* parent) : QObject(parent), data(0) {}
public slots:
void slot1() {
someOperation();
}
void slot2() {
someOperation();
}
void slot3() {
someOperation();
}
private:
void someOperation() {
QMutexLocker lk(&mutex);
data++;
QMessageBox::warning(NULL, "warning", "warning");
data--;
assert(data == 0);
}
int data;
QMutex mutex; //protect data
};
class Worker: public QThread {
Q_OBJECT
public:
explicit Worker(QObject* parent) : QThread(parent) {}
protected:
virtual void run() {
// some complicated data processing
emit signal1();
// other complicated data processing
emit signal2();
// much complicated data processing
emit signal3();
qDebug() << "end run";
}
signals:
void signal1();
void signal2();
void signal3();
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
A* a = new A(&app);
Worker* w = new Worker(a);
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
w->start();
return app.exec();
}
There is a thread that will emit three signals, all of them queued connected to an instance of class A, and all class A' slots will call to someOperation, and someOperation is protected by mutex and it will popup a message box.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
It seems slot2 is invoked when slot1's message box still doing modal, in main thread, but at that time slot1 has lock mutex, so deadlock.
How to change the code to avoid deadlock?
Update:(Jan.17, 2019)
What I want archive is that: slot2 not be execute before slot1 finished.
What should be kept are:
worker is a background thread to process data, cost long time; so, whatever, the three signals will emit from other thread.
worker should not blocked by emitting signals.
slots should execute in main thread, because they will update GUI.
someOperation is not reentrant.
The requirement that "someOperation is not reentrant" is an odd one. What should happen if reentrancy is attempted? Given that someOperation can only be called from the main thread I can only see two options...
Block completely with mutex/barrier etc. as you have tried.
Block based on a recursion level counter and spin the event loop until that counter decrements to zero.
1) Will block the thread's event loop completely preventing the current message dialog from functioning correctly.
2) Will allow all message dialogs simultaneously rather then serialising them.
Rather than trying to make someOperation non-reentrant I think you need to make sure you use in a way that won't result in reentrancy.
One option might be to make use of a separate QObject derived class instance on its own QThread. Consider the following...
class signal_serialiser: public QObject {
Q_OBJECT;
signals:
void signal1();
void signal2();
void signal3();
};
If an instance of signal_serialiser is moved to its own thread it can act as a queue to buffer and forward the various signals if suitable connection types are used. In your code you currently have...
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
Change that to...
signal_serialiser signal_serialiser;
QObject::connect(w, SIGNAL(signal1()), &signal_serialiser, SIGNAL(signal1()));
QObject::connect(w, SIGNAL(signal2()), &signal_serialiser, SIGNAL(signal2()));
QObject::connect(w, SIGNAL(signal3()), &signal_serialiser, SIGNAL(signal3()));
/*
* Note the use of Qt::BlockingQueuedConnection for the
* signal_serialiser --> A connections.
*/
QObject::connect(&signal_serialiser, SIGNAL(signal1()), a, SLOT(slot1()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal2()), a, SLOT(slot2()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal3()), a, SLOT(slot3()), Qt::BlockingQueuedConnection);
QThread signal_serialiser_thread;
signal_serialiser.moveToThread(&signal_serialiser_thread);
signal_serialiser_thread.start();
I've only done basic testing but it appears to give the desired behaviour.
That's because your function void someOperation() is not reentrant.
The static functions of QMessageBox span their own event loop, which calls QCoreApplication::processEvents() repeatedly:
Execution of the first invocation of someOperation() gets stuck at QMessageBox::warning(...).
In there, exec() calls processEvents(), 3. which sees the second signal
and invokes someOperation() again
where trying to re-lock mutex fails.
How to resolve this depends on what you want to achieve...
About your general approach to QThread: You're doing it wrong.
(That link gives a good start into the topic, but not a complete solution.)
You create and start a background thread. But that thread will only emit the three signals and then finish.
The slots will be called inside the main (GUI) event loop, because that's the thread affinity of your A *a.
To make the slots be executed in the background, you need to:
create your A instance without a parent: A *a = new A();
create your Worker instance with the app as parent: Worker *w = new Worker(&app); (or with nothing, at least not with a)
change the thread affinity of your A instance: a->moveToThread(Worker);
don't override Worker::run(), or if you really want to (see point 5), call the base implementation: QThread::run();
emit the signals from main (you can emit them from run(), but that's not necessary).

Avoid having to qRegisterMetaType (pointer vs reference), concern about const

Given the signal:
void dbConnected(const QSqlDatabase &db);
I learned (from Qt Communication betwen threads, app design) how to avoid having to use
qRegisterMetaType<QSqlDatabase>("QSqlDatabase");
Just changing the signal to this form:
void dbConnected(QSqlDatabase *db);
And, in the slot side I'll use something like this:
void onDBConnected(QSqlDatabase * const db);
I'm concerned with the usage of db (as in the beginning I've made the reference const), so I make it const here (in the slot side). I've tried to do the same in the signal side with
void dbConnected(QSqlDatabase * const db);
But doing so I have the runtime error (mentioned in Qt Communication betwen threads, app design) back. So I tried another form, which seems to do the job:
void dbConnected(QSqlDatabase *db) const;
Am I in the right direction?
Am I in the right direction?
Maybe. First, make sure that you know that you cannot pass the database to an object living in another thread. That was one of the major mistakes you did in the code in the other question. Don't do that anymore.
If you're passing an object via reference, it must be copyable. A QSqlDatabase is copyable after you open it. So you're OK here, too.
But you might not need to pass the database reference at all. QSqlDatabase assigns a name to each connection. Instead of passing the databases by value or by pointer, you can pass their connection names instead, and use QSqlDatabase::database to get a database object representing a given connection.
For example:
class Opener : public QObject {
Q_OBJECT
QSqlDatabase m_db;
public:
Q_SIGNAL void dbOpened(const QString &);
void open() {
m_db.addDatabase("FOO", "cats");
...
if (m_db.open()) emit dbOpened(m_db.connectionName());
}
};
class DbUser : public QObject {
Q_OBJECT
QSqlDatabase m_db;
public:
Q_SLOT void onDbOpened(const QString & conn) {
m_db = QSqlDatabase::database(conn);
}
...
};
As you can see, the dbOpened signal emits not a database, but a database connection name, and then the various objects that wish to use that connection can retrieve the database object (handle) by name.

Using POSIX threads in Qt Widget App

I'm relatively new to both Qt and pthreads, but I'm trying to use a pthread to work in the background of basic test app I'm making. I'm aware of the Qt Frameworks own threading framework - but there's a lot of complaint surrounding it so I'd like to use pthread if possible. The code is as below
#include "drawwindow.h"
#include "ui_drawwindow.h"
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include "QThread"
pthread_t th1;
DrawWindow::DrawWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::DrawWindow)
{
ui->setupUi(this);
}
DrawWindow::~DrawWindow()
{
delete ui;
}
void DrawWindow::on_pushButton_clicked()
{
pthread_create(&th1, NULL, &DrawWindow::alter_text, NULL);
}
void DrawWindow::alter_text()
{
while(1)
{
ui->pushButton->setText("1");
QThread::sleep(1);
ui->pushButton->setText("one");
QThread::sleep(1);
}
}
With the header
#ifndef DRAWWINDOW_H
#define DRAWWINDOW_H
#include <QMainWindow>
namespace Ui {
class DrawWindow;
}
class DrawWindow : public QMainWindow
{
Q_OBJECT
public:
explicit DrawWindow(QWidget *parent = 0);
~DrawWindow();
void alter_text();
private slots:
void on_pushButton_clicked();
private:
Ui::DrawWindow *ui;
};
#endif // DRAWWINDOW_H
And I'm getting the error
error: cannot convert 'void (DrawWindow::*)()' to 'void* (*)(void*)' for argument '3' to 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)'
pthread_create(&th1, NULL, &DrawWindow::alter_text, NULL);
^
Does anyone know what is wrong?
TL;DR: The way you're using pthreads is precisely the discouraged way of using QThread. Just because you use a different api doesn't mean that what you're doing is OK.
There's absolutely no problem with either QThread or std::thread. Forget about pthreads: they are not portable, their API is C and thus abhorrent from a C++ programmer's perspective, and you'll be making your life miserable for no reason by sticking to pthreads.
Your real issue is that you've not understood the concerns with QThread. There are two:
Neither QThread nor std::thread are destructible at all times. Good C++ design mandates that classes are destructible at any time.
You cannot destruct a running QThread nor std::thread. You must first ensure that it's stopped, by calling, respectively QThread::wait() or std::thread::join(). It wouldn't have been a big stretch to have their destructors do that, and also stop the event loop in case of QThread.
Way too often, people use QThread by reimplementing the run method, or they use std::thread by running a functor on it. This is, of course, precisely how you use pthreads: you run some function in a dedicated thread. The way you're using pthreads is just as bad as the discouraged way of using QThread!
There are many ways of doing multithreading in Qt, and you should understand the pros and cons of each of them.
Thus, how do you do threading in C++/Qt?
First, keep in mind that threads are expensive resources, and you should ideally have no more threads in your application than the number of available CPU cores. There are some situations when you're forced to have more threads, but we'll discuss when it's the case.
Use a QThread without subclassing it. The default implementation of run() simply spins an event loop that allows the objects to run their timers and receive events and queued slot calls. Start the thread, then move some QObject instances to it. The instances will run in that thread, and can do whatever work they need done, away from the main thread. Of course, everything that the objects do should be short, run-to-completion code that doesn't block the thread.
The downside of this method is that you're unlikely to exploit all the cores in the system, as the number of threads is fixed. For any given system, you might have exactly as many as needed, but more likely you'll have too few or too many. You also have no control over how busy the threads are. Ideally, they should all be "equally" busy.
Use QtConcurrent::run. This is similar to Apple's GCD. There is a global QThreadPool. When you run a functor, one thread from the pool will be woken up and will execute the functor. The number of threads in the pool is limited to the number of cores available on the system. Using more threads than that will decrease performance.
The functors you pass to run will do self-contained tasks that would otherwise block the GUI leading to usability problems. For example, use it to load or save an image, perform a chunk of computations, etc.
Suppose you wish to have a responsible GUI that loads a multitude of images. A Loader class could do the job without blocking the GUI.
class Loader : public QObject {
Q_OBJECT
public:
Q_SIGNAL void hasImage(const QImage &, const QString & path);
explicit Loader(const QStringList & imagePaths, QObject * parent = 0) :
QObject(parent) {
QtConcurrent::map(imagePaths, [this](const QString & path){
QImage image;
image.load(path);
emit hasImage(image, path);
});
}
};
If you wish to run a short-lived QObject in a thread from the thread pool, the functor can spin the event loop as follows:
auto foo = QSharedPointer<Object>(new Object); // Object inherits QObject
foo->moveToThread(0); // prepares the object to be moved to any thread
QtConcurrent::run([foo]{
foo->moveToThread(QThread::currentThread());
QEventLoop loop;
QObject::connect(foo, &Object::finished, &loop, &QEventLoop::quit);
loop.exec();
});
This should only be done when the object is not expected to take long to finish what it's doing. It should not use timers, for example, since as long as the object is not done, it occupies an entire thread from the pool.
Use a dedicated thread to run a functor or a method. The difference between QThread and std::thread is mostly in that std::thread lets you use functors, whereas QThread requires subclassing. The pthread API is similar to std::thread, except of course that it is C and is awfully unsafe compared to the C++ APIs.
// QThread
int main() {
class MyThread : public QThread {
void run() { qDebug() << "Hello from other thread"; }
} thread;
thread.start();
thread.wait();
return 0;
}
// std::thread
int main() {
// C++98
class Functor {
void operator()() { qDebug() << "Hello from another thread"; }
} functor;
std::thread thread98(functor);
thread98.join();
// C++11
std::thread thread11([]{ qDebug() << "Hello from another thread"; });
thread11.join();
return 0;
}
// pthread
extern "C" void* functor(void*) { qDebug() << "Hello from another thread"; }
int main()
{
pthread_t thread;
pthread_create(&thread, NULL, &functor, NULL);
void * result;
pthread_join(thread, &result);
return 0;
}
So, what is this good for? Sometimes, you have no choice but to use a blocking API. Most database drivers, for example, have blocking-only APIs. They expose no way for your code to get notified when a query has been finished. The only way to use them is to run a blocking query function/method that doesn't return until the query is done. Suppose now that you're using a database in a GUI application that you wish to remain responsive. If you're running the queries from the main thread, the GUI will block each time the database query run. Given long-running queries, a congested network, a dev server with a flaky cable that makes the TCP perform on par with sneakernet... you're facing huge usability issues.
Thus, you can't but have to run the database connection on, and execute the database queries on a dedicated thread that can get blocked as much as necessary.
Even then, it might still be helpful to use some QObject on the thread, and spin an event loop, since this will allow you to easily queue the database requests without having to write your own thread-safe queue. Qt's event loop already implements a nice, thread-safe event queue so you might as well use it. For example, with a note that Qt's SQL module can be used from one thread only - thus you can't prepare QSQLQuery in the main thread :(
Note that this example is very simplistic, you'd likely want to provide thread-safe way of iterating the query results, instead of pushing the entire query's worth of data at once.
class DBWorker : public QObject {
Q_OBJECT
QScopedPointer<QSqlDatabase> m_db;
QScopedPointer<QSqlQuery> m_qBooks, m_query2;
Q_SLOT void init() {
m_db.reset(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE")));
m_db->setDatabaseName(":memory:");
if (!m_db->open()) { emit openFailed(); return; }
m_qBooks.reset(new QSqlQuery(*m_db));
m_qBooks->prepare("SELECT * FROM Books");
m_qCars.reset(new QSqlQuery(*m_db));
m_qCars->prepare("SELECT * FROM Cars");
}
QList<QVariantList> read(QSqlQuery * query) {
QList<QVariantList> result;
result.reserve(query->size());
while (query->next()) {
QVariantList row;
auto record = query->record();
row.reserve(record.count());
for (int i = 0; i < recourd.count(); ++i)
row << query->value(i);
result << row;
}
return result;
}
public:
typedef QList<QVariantList> Books, Cars;
DBWorker(QObject * parent = 0) : QObject(parent) {
QObject src;
connect(&src, &QObject::destroyed, this, &DBWorker::init, Qt::QueuedConnection);
m_db.moveToThread(0
}
Q_SIGNAL void openFailed();
Q_SIGNAL void gotBooks(const DBWorker::Books &);
Q_SIGNAL void gotCars(const DBWorker::Cars &);
Q_SLOT void getBooks() {
Q_ASSERT(QThread::currentThread() == thread());
m_qBooks->exec();
emit gotBooks(read(m_qBooks));
}
Q_SLOT void getCars() {
Q_ASSERT(QThread::currentThread() == thread());
m_qCars->exec();
emit gotCars(read(m_qCars));
}
};
Q_REGISTER_METATYPE(DBWorker::Books);
Q_REGISTER_METATYPE(DBWorker::Cars);
// True C++ RAII thread.
Thread : public QThread { using QThread::run; public: ~Thread() { quit(); wait(); } };
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
Thread thread;
DBWorker worker;
worker.moveToThread(&thread);
QObject::connect(&worker, &DBWorker::gotCars, [](const DBWorker::Cars & cars){
qDebug() << "got cars:" << cars;
qApp->quit();
});
thread.start();
...
QMetaObject::invokeMethod(&worker, "getBooks"); // safely invoke `getBooks`
return app.exec();
}
Change void DrawWindow::alter_text() to void* DrawWindow::alter_text(void*) and return pthread_exit(NULL);.

connect in QT issue - no connection?

I have a custom class derived from QGraphicsPixmapItem. Its called GraphPixmapItemCustom and it's overloaded method is:
void GraphPixmapItemCustom::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsPixmapItem::mousePressEvent(event);
GraphMarkItemCustom *ptr;
if(event->button() == Qt::RightButton)
{
qDebug("Before emit");
emit addPoint(QPointF(event->pos().x(), event->pos().y()));
qDebug("After emit");
markList.append(new GraphMarkItemCustom(QPointF(event->pos().x(), event->pos().y())));
ptr = markList.last();
markGroup->addToGroup(ptr);
//this->scene()->addItem(ptr);
}
}
the signal is declared at header:
signals:
void addPoint(QPointF position);
In main class that has a pointer to object of class GraphPixmapItemCustom called
private:
GraphPixmapItemCustom *pixItemRGB;
and in the main class I have a slot called:
private slots:
void pointAdd(QPointF position);
In the main class constructor I have a connection:
connect(pixItemRGB, SIGNAL(addPoint(QPointF)), this, SLOT(pointAdd(QPointF)));
In the slot I have only qDebug("YUPPY IT ACTUALLY WORKS!");
But the slot is not beeing fired. Why? I have deleted all moc files and everything that didn't have to be there. So only .pro, .h and .cpp files along with .ui forms where neccesary were left.
I have checked most hits at Google. What is the best (I'm not sured - maybe i modified something) that it worked! I remember the working effects of this connection. Help!
You have to connect the signal after creating the GraphPixmapItemCustom object with the new operator.

How to delete a QProcess instance correctly?

I have a class looking like this:
class FakeRunner : public QObject
{
Q_OBJECT
private:
QProcess* proc;
public:
FakeRunner();
int run()
{
if (proc)
return -1;
proc = new QProcess();
QStringList args;
QString programName = "fake.exe";
connect(comp, SIGNAL(started()), this, SLOT(procStarted()));
connect(comp, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(procError(QProcess::ProcessError)));
connect(comp, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(procFinished(int, QProcess::ExitStatus)));
proc->start(programName, args);
return 0;
};
private slots:
void procStarted() {};
void procFinished(int, QProcess::ExitStatus) {};
void procError(QProcess::ProcessError);
}
Since "fake.exe" does not exist on my system, proc emits the error() signal. If I handle it like following, my program crashes:
void FakeRunner::procError(QProcess::ProcessError rc)
{
delete proc;
proc = 0;
}
It works well, though, if I don't delete the pointer. So, the question is how (and when) should I delete the pointer to QProcess? I believe I have to delete it to avoid a memory leak. FakeRunner::run() can be invoked many times, so the leak, if there is one, will grow.
Thanks!
You can't delete QObject instance inside slot which is connected to a signal in this instance using normal delete operator. This is due to the fact that if signal and slot connected using direct connection then the slot actually called from the signal implementation made by moc. This is like attempt to delete this; from inside the member of a class. There is a solution QObject::deleteLater(). Object will be deleted by Qt event loop inside events processing function. So you need to call proc->deleteLater() in your case.
And you don't need to disconnect signal from slot since Qt do it automatically when QObject is deleted.

Resources