I have a class Messenger with two internal object pointers:
std::unique_ptr<QThread> stdin_receiver_thread_ = nullptr;
std::unique_ptr<ReceiverWorker> stdin_receiver_ = nullptr;
In the constructor of the Messenger I create these objects and assign them to these smart pointers like so:
Messenger::Messenger(QObject *parent) : QObject(parent) {
// create the objects
stdin_receiver_thread_ = std::make_unique<QThread>();
stdin_receiver_ = std::make_unique<ReceiverWorker>();
//
qDebug() << "stdin_receiver_thread_:" << stdin_receiver_thread_.get()->thread();
// I assign the worker to this the newly created thread
stdin_receiver_->moveToThread(stdin_receiver_thread_.get());
//
connect(stdin_receiver_thread_.get(), &QThread::started, stdin_receiver_.get(), &ReceiverWorker::process);
connect(stdin_receiver_.get(), &ReceiverWorker::receivedMessage, stdin_receiver_thread_.get(), &QThread::quit);
connect(stdin_receiver_.get(), &ReceiverWorker::receivedMessage, stdin_receiver_.get(), &QObject::deleteLater);
connect(stdin_receiver_thread_.get(), &QThread::finished, stdin_receiver_thread_.get(), &QObject::deleteLater);
stdin_receiver_thread_->start();
}
and inside my ReceiverWorker::process()
i call
qDebug() << "Receiverworker currentThread:" << QThread::currentThread();
Now, those two qDebug() calls print different values: i.e.:
stdin_receiver_thread_: QThread(0x20a24e57ba0)
Receiverworker currentThread: QThread(0x20a2e6f58e0)
so it's like ReceiverWorker works in some different thread than I want it to. What am I doing wrong?
It's doing exactly what it should. The term stdin_receiver_thread_.get()->thread(); yields the QThread in which stdin_receiver_thread_ as a QObject lives. In other terms your main thread or wherever Messenger was constructed.
If you had instead just written:
qDebug() << "stdin_receiver_thread_:" << stdin_receiver_thread_.get();
you would have gotten the expected output.
std::unique_ptr<QThread>
You should not be using std::unique_ptr with a QObject for which you call deleteLater(). That inevitably results in a double-free / heap corruption.
You're calling QObject::thread() on a QThread object. The docs say: "Returns the thread in which the object lives." The QThread is an object that lives in the main thread. I think your function is working as expected, you just weren't comparing the right values for your qDebugs.
Related
I've a main thread for the GUI, in which is run the MainWindow object,
in its constructor I create a new worker object and a QThread object and the i move the worker to the thread, the problem is that when printing their ids they are the same:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
QThread *t_pc = new QThread;
worker *pc_w;
pc_w = new pc_worker();
pc_w->moveToThread(t_pc);
t_pc->start();
pc_w->initialize();
// ...
}
worker.cpp
worker::worker(QObject *parent) : QObject(parent) {
}
void worker::initialize() {
std::cout << "INITIALIZE " << QThread::currentThreadId() << std::endl;
}
I get:
MAIN_ID 0x7f4009ccb780
INITIALIZE 0x7f4009ccb780
What's wrong?
Answer: moveToThread does work, just not in the way you expected.
Looks like after calling pc_w->moveToThread(t_pc) you expected all member functions of pc_w to be called in t_pc now. However, that is not what moveToThread() does.
The purpose of moveToThread() is to change QObject "thread affinity" or in other words thread where an object lives. But on the basic level everything it gives you is just the guarantee that all the object`s slots connected to any signal via Qt::QueuedConnection will be invoked (run) in that particular thread.
Member functions still run in the thread you invoke them from. In your case, you call initialize() from the GUI thread, so QThread::currentThreadId() gives you the id of that thread.
I really recommend to read official doc on thread affinity and this article on thread event loops.
QThread* thread = new QThread;
Worker* worker = new Worker;
// Uses Qt::AutoConnection (default)
// which will be transalted into Qt::QueuedConnection
QObject::connect(thread, &QThread::started, worker, &Worker::initialize);
std::cout<<"MAIN_ID "<< QThread::currentThreadId()<<std::endl;
worker->moveToThread(thread);
thread->start();
Output:
MAIN_ID 0000000000003E5C
INITIALIZE 0000000000003DAC
The solution trivelt proposed artificially puts "call initialize()" event into the thread event loop reaching the same effect. However, it does not perform any compile-time checks ("initialize" is specified as a string).
Try to use invokeMethod instead of diretly calling pc_w->initialize(), e.g.:
QMetaObject::invokeMethod(pc_w, "initialize", Qt::QueuedConnection);
Your initialize() method should be SLOT or SIGNAL in this case.
My situation is that I have a QWidget-derived class, MyWidget, that will create a QThread-derived class (WorkerThread) to do some uninterruptible, blocking work in its run() method. The results of this are a heap-allocated instance of a QObject-derived class (DataClass) which is then received and processed by MyWidget. MyWidget is a transitory widget, though, and may be deleted while WorkerThread is still running due to user action.
Here's some pseudo-code to illustrate this:
#include <QThread>
#include <QWidget>
class DataClass : public QObject {
Q_OBJECT
public:
// contains some complex data
};
class WorkerThread : public QThread {
Q_OBJECT
public:
virtual void run() {
DataClass *result = new DataClass;
doSomeReallyLongUninterruptibleWork(result);
emit workComplete(result);
}
signals:
void workComplete(DataClass *);
};
class MyWidget : public QWidget {
Q_OBJECT
public:
void doBlockingWork() {
WorkerThread *worker = new WorkerThread;
connect(worker, &WorkerThread::finished, worker, &WorkerThread::deleteLater);
connect(worker, &WorkerThread::workComplete, this, &MyWidget::processData);
worker->start();
}
public slots:
void processData(DataClass *result) {
// Do some stuff
delete result;
// Assuming MyWidget still exists when WorkerThread has finished, no memory has leaked
}
};
Normally the correct "Qt" way to return the results of a worker thread is to have it emit a signal with its arguments being the result of its work, as illustrated above. That's fine for data that can be copied, but since the result is a pointer to a heap-allocated object, I have to be careful to make sure that memory gets freed.
And normally that wouldn't be a problem, because since WorkerThread has finished, I can safely pass the pointer to DataClass to MyWidget, have it process DataClass, and then free it.
The problem is that, as I said earlier, MyWidget is transitory and may be destroyed before WorkerThread is finishing. In this scenario, how can I ensure that the instance of DataClass gets freed one way or the other?
In particular, I'm looking for solutions that have some elegance to them, meaning that it takes advantage of Qt's features and preferably makes it so that WorkerThread maintains its separation from MyWidget so that WorkerThread doesn't need to know anything about it or any other class that might create it. I'm also open to ideas that improve upon the pattern that I'm already using.
Use smart pointer (e.g., QSharedPointer) instead a normal pointer:
DataClass *result = new DataClass;
should be replaced with
QSharedPointer<DataClass> result = QSharedPointer<DataClass>(new DataClass);
Then, you could safely pass it somewhere and do not worry about deleting it. When it is out of the last scope where it can be used, the object will be automatically destroyed.
The worker should push the result to the main thread, to indicate that it's safe to use there (per QObject semantics). The result should be auto-deleted in the main thread after everyone interested has been notified of the completion of the work. It is a minimal change:
void run() override {
auto result = new DataClass;
doSomeReallyLongUninterruptibleWork(result);
result->moveToThread(qApp->thread()); // added
emit workComplete(result);
QObject::connect(this, &QThread::finished, result, &QObject::deleteLater); // added
}
You're guaranteed that deleteLater will be invoked after the last handler of workComplete has finished in the main thread.
A single object in the main thread might wish to retain the results longer. This can be indicated by setting the parent on the result object. The object shouldn't be deleted then:
...
QObject::connect(this, &QThread::finished, result, [result]{
if (!result->parent()) result->deleteLater();
});
If you intend that multiple objects in the main thread retain the results longer, you should be using a QSharedPointer in the workComplete's argument, and you must never set the parent of the results: a non-null parent and a QSharedPointer are mutually incompatible: the former indicates a unique ownership by a parent, the latter indicates a shared ownership.
It is necessary to move the DataClass object to the main thread to avoid a race on DataClass::thead() and to allow deleteLater to work:
Worker Thread: emit workComplete(result)
Main Thread: start using result, result.thread() is the worker instance.
Worker Thread: finishes
Main Thread: result.thread() is now nullptr while the main thread is using it.
This might not be a problem, but usually indicates poor design. As soon as you start using more QObject features of DataClass, it turns the latent bug into a real bug: e.g. deleteLater won't work, timers won't work, etc.
Furthermore, destructing a QObject in any thread other than its thread is not supported. Suppose that you had your original code. The following could happen and leads to undefined behavior:
Worker Thread: emit workComplete(result)
Main Thread: start using result, result.thread() is the worker instance.
Main Thread: delete result. QObject::~QObject is invoked in qApp->thread() but result->thread() is the different, still live instance of the worker thread.
If you wish to catch such issues, add:
DataClass::~DataClass() {
Q_ASSERT(thread() == nullptr || thread() == QThread::currentThread());
...
}
It's OK to destruct a threadless object, but such objects are not fully functional: you can't deleteLater them, their timers don't work, they don't receive events, etc.
The necessity of a parent check prior to deleteLater depends on whether you intend to prolong the existence of the result past the code connected to workComplete.
The "obvious" use of a shared pointer doesn't make it clear which thread can safely access the result iff the result isn't thread-safe. It also does nothing by itself to fix the fact that once the worker finishes, the QObject is half-functional as there's no event loop associated with it. I believe that your intent is that only one thread may own the result, so that its methods don't have to be thread-safe. Luckily, QObject's semantics already express this clearly: the object's thread() is the one authorized to act on the object.
Any recipients of workComplete in the main thread will get to process the results before they vanish. If any object in the main thread wants to take ownership of the result, it can - by setting the parent. Otherwise, as soon the workComplete handlers are done, if none have claimed ownership, the result will get deleted from the main event loop.
Change the QTimer::singleShot(1000, w.data(), [&]{ w.reset(); }) timer to 2500ms to have the widget outlive the worker thread and note the difference in behavior depending on whether it claimed ownership.
Complete example:
// https://github.com/KubaO/stackoverflown/tree/master/questions/worker-shared-37956073
#include <QtCore>
struct DataClass : public QObject {
DataClass() { qDebug() << __FUNCTION__; }
~DataClass() { qDebug() << __FUNCTION__; }
};
void doSomeReallyLongUninterruptibleWork(DataClass*) { QThread::sleep(2); }
class WorkerThread : public QThread {
Q_OBJECT
public:
void run() override {
auto result = new DataClass;
doSomeReallyLongUninterruptibleWork(result);
result->moveToThread(qApp->thread());
emit workComplete(result);
QObject::connect(this, &QThread::finished, result, [result]{
if (!result->parent()) {
qDebug() << "DataClass is unclaimed and will deleteLater";
result->deleteLater();
}
});
}
Q_SIGNAL void workComplete(DataClass*);
};
class MyWidget : public QObject {
void processData(DataClass * result) {
// Do stuff with result
// Retain ownership (optional)
if (true) result->setParent(this);
}
public:
void doBlockingWork() {
auto worker = new WorkerThread;
connect(worker, &WorkerThread::workComplete, this, &MyWidget::processData);
connect(worker, &WorkerThread::finished, worker, &WorkerThread::deleteLater);
worker->start();
}
~MyWidget() { qDebug() << __FUNCTION__; }
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
QScopedPointer<MyWidget> w{new MyWidget};
w->doBlockingWork();
QTimer::singleShot(1000, w.data(), [&]{ w.reset(); });
QTimer::singleShot(3000, qApp, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
You could also forgo the use of an explicit thread, and use QtConcurrent::run instead. There's no clear advantage to that, I'm showing it here just to indicate that either approach is feasible.
#include <QtConcurrent>
struct DataClass : public QObject {
Q_SIGNAL void ready();
Q_OBJECT
};
// Let's not pollute the default pool with long-running stuff
Q_GLOBAL_STATIC(QThreadPool, longPool)
class MyWidget : public QObject {
void processData(DataClass * result) {
// Do stuff with result
// Retain ownership (optional)
if (true) result->setParent(this);
}
public:
void doBlockingWork() {
auto result = new DataClass;
connect(result, &DataClass::ready, this, [=]{ MyWidget::processData(result); });
result->moveToThread(nullptr);
QtConcurrent::run(longPool, [result]{
result->moveToThread(QThread::currentThread());
doSomeReallyLongUninterruptibleWork(result);
result->moveToThread(qApp->thread());
emit result->ready();
QTimer::singleShot(0, result, [result]{
if (!result->parent()) result->deleteLater();
});
});
}
};
If I have the most standard code of using a QThread like this:
myClass* object = new myClass();
QThread* worker = new QThread();
object->moveToThread(worker);
worker->start();
Then what is the proper way to delete object and the proper way to quit the worker thread?
If I don't delete object there will be memory leakage.
If I don't quit worker, when I close the application, there will be warning said that QThread is destroyed while it is still running.
To delete your object object, you can connect the QThread::finished signal of your worker object to the QObject::deleteLater slot of your object object.
And to quit your thread, you can call QThread::quit and QThread::wait in the destructor of your class (or whenever you need to stop your thread).
MyClass::~MyClass()
{
thread->quit();
thread->wait();
...
}
To delete your worker object, you can just set a parent to it, or make it an automatic member variable. You can also use a smart pointer for it.
By the way, your naming convention is a bit odd. The QThread object in your case is not a worker, it just manages the thread. The myClass object would be the worker in your case.
Here's a basic usage:
Define a worker class:
class MyWorkerClass {
signals:
void Finished();
public slots:
void RunCode(){
//...
// add your code here
//...
emit Finished();
}
}
How to use your worker class:
MyWorkerClass * workerObject = new MyWorkerClass();
QThread * workerThread = new QThread();
workerObject->moveToThread(workerThread);
connect(workerThread, &QThread::started, workerObject, &MyWorkerClass::RunCode);
connect(workerObject, &MyWorkerClass::Finished, workerThread, &QThread::quit);
workerThread->start();
workerObject->deleteLater();
Connecting QThread::finished and QObject::deleteLater is wrong. If signal QThread::finished is emitted this means that thread event loop will not run again so slot QObject::deleteLater will not be called. So accepted answer is wrong.
It is better to do it like that:
myClass* object = new myClass();
QThread* worker = new QThread(parent);
object->moveToThread(worker);
connect(object, &QObject::destroyed, worker, &QThread::quit, Qt::DirectConnection);
connect(someObject, SIGNAL(stoItSignal()), object, &QObject::deleteLater);
worker->start();
At some point it might be needed to wait for tread, (for example when main window is destroyed) to clean up things, so this statement could be useful (in this case Qt::DirectConnection in code above is obligatory):
object->deleteLater();
worker->wait(3000);
I have a (somewhat) simple program that creates new threads, one per connection to a socket:
void TelnetServer::incomingConnection(qintptr socketDescriptor)
{
TelnetConnection *thread = new TelnetConnection(socketDescriptor);
connect(thread, SIGNAL(shutdownRequested()), m_controller, SLOT(shutdown()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
after a new thread is created, I output to qDebug a list of all children of the parent that created the QThreads (TelnetConnection) like this:
QList<QObject*> activeTelnetConnections = m_telnetserver->findChildren <QObject *> (); // Find all QThreads that children of telnetserver
qDebug() << "Children: " << activeTelnetConnections;
Since my QThreads decend from Qobject, I expect to see a list of QThreads and more. However, I can't find the Qthreads! This is all I see:
Children: (QNativeSocketEngine(0x7eb880) , QSocketNotifier(0x7ea5f0) )
Why do I not see the child threads? Does this mean the threads are not associated with the parent object anymore? Or am I doing something wrong here...
Does this mean the threads are not associated with the parent object anymore?
It may have never been associated. When you construct the thread, you need to pass the parent to it, however your TelnetConnection seems to be wrong as it does not expect a parent argument, or you do not pass that which internally passes that further to the base class with the following constructor.
QThread(QObject * parent = 0)
or you have to call setParent() on it later.
void QObject::setParent(QObject * parent)
This would mean thread.setParent(this); for your code, but I would rather suggest to fix either your thread class constructor or the invocation of it.
Alternatively, you can also set the child for the TelnetConnection explicit, but I would suggest the proper construction if possible.
EDIT:
I tried doing what you guys told me in comments ... :
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
This produces even more errors:
QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file c:\ndk_buildrepos\qt-desktop\src\corelib\thread\qthread_win.cpp, line 542
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
QObject::killTimers: timers cannot be stopped from another thread
I am having problems with this error ... I'm stuck on this for 2 days already and can't get a solution.
Header:
class Citizen : public QThread
{
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
};
Implementation:
Citizen::Citizen(QObject * parent)
{
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void Citizen::run()
{
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
}
When manager->get() gets executed, I get the following error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0xc996cf8), parent's thread is QThread(0xaba48d8), current thread is Citizen(0xca7ae08)
When eLoop.exec() gets executed:
QObject::startTimer: timers cannot be started from another thread
I start this thread in the following manner:
Citizen * c = new Citizen(this);
c->start();
Why does this happen? How to solve this?
QObject: Cannot create children for a parent that is in a different thread.
You get this because you are creating the QNetworkAccessmanager in the constructor of Citizen, which is being called in the "original" thread. When the Citizen object is moved to the new thread the QNetworkAccessmanager still has its thread affinity set to the original thread but in the run call it will attempt to create the QNetworkReply object ( and probably other objects aswell ) in the new thread. Which produces the warning above.
If you create the manager in the run slot(or at any point after the Citizen object is moved to the new thread) that will not happen.
However you still have some issues. For instance, the Citizen class really doesn't need to be a QThread. It needlessly complicates it. It will suffice for your purpose(afaict) to subclass a QObject. Just make a normal slot and connect that to the QThread::started() signal. And as OrcunC pointed out you need to make sure that the QThread instance is properly scoped.
For more on threading: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/
Example:
QThread *thread = new QThread;
thread->start();
Citizen *worker = new Citizen;
worker->moveToThread(thread);
//startWorking can be equivalent of the run function
//in your current implementation and this is where you should
//create the QNetworkAccessManager
QMetaObject::invokeMethod(worker,"startWorking");
I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.
If you do this
void mtMethod () {
Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);
connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
}
The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :
class myClass
{
virtual ~myClass ();
QThread mythread;
};
myClass::~myClass
{
mythread.stop ();
}
void myClass::mtMethod () {
Citizen * c = new Citizen(this);
c->moveToThread(&mythread);
connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
mythread.start();
}
I don't believe the new thread exists until run is called. So the constructor is a different thread than run(). What happens if you move the creation of the manager object from the constructor to run()? I imagine that will fix the first error, if not the timer error as well.
Also, I think many people are still building threads the way you are, but you might want to check out this.
You need to consider thread affinity. That error message is not lying or insane, it's telling you exactly what's wrong.
Your problems are mostly due to trying to subclass QThread. Even though the documentation recommends it, it is not the best way to use QThread. Please see this question and answer for more information and links.
I haven't figured out the startTimers error although it could be related to the first one. In any case, you should be able to fix the first error. I have run into this problem in Qt a few times and I find this to be the "best" way to work around it is to create an initialize function and a cleanUp function. All members of the class are pointers that are initialized to NULL until run is called. Note that "best" is in quotes because there are sure to be differing opinions but it works for most situations for me.
Header
class Citizen : public QThread {
Q_OBJECT
QNetworkAccessManager * manager;
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
Citizen(QObject * parent);
void run();
private:
void initialize();
void cleanUp();
};
Implementation
Citizen::Citizen(QObject * parent) :
manager(NULL) {
}
void Citizen::onReplyFinished(QNetworkReply* net_reply) {
emit onFinished(net_reply);
}
void Citizen::run() {
initialize();
manager->get(QNetworkRequest(QUrl("http://google.com"));
QEventLoop eLoop;
connect(manager, SIGNAL( finished( QNetworkReply * ) ),
&eLoop, SLOT(quit()));
eLoop.exec(QEventLoop::ExcludeUserInputEvents);
qDebug() << "loaded google!";
exec();
cleanUp();
}
void Citizen::initialize() {
manager = new QNetworkAccessManager;
connect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void Citizen::cleanUp() {
delete manager;
disconnect(_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}