I'm very new to using QThread
. I'm using QThread
to grab images from an Axis Ip Camera. In the following snippet of the code I'm moving the camera class to a new thread:
QThread camThread;
camera = new AxisNetworkCamera();
camera->moveToThread(&camThread);
camThread.start();
connect(camera, SIGNAL(imageUpdate(QImage)), this, SLOT(upDateImage(QImage)));
connect(camera, SIGNAL(cameraDisconnected()), this, SLOT(cameraDisconnected()));
connect(&camThread, &QThread::finished, &camThread, &QThread::deleteLater);
connect(camera, &AxisNetworkCamera::destroyed, &camThread, &QThread::quit);
I'm invoking the function that starts the camera:
QMetaObject::invokeMethod(camera, "deviceStartup", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(streamUrl)));
The application runs fine and also closes fine when I close it, but what I'm worried is about a couple of warning messages.
First one is when I start the camera:
Type conversion already registered from type QPair<QByteArray,QByteArray> to type QtMetaTypePrivate::QPairVariantInterfaceImpl
2nd one is when I close the application:
QThreadStorage: Thread 0x7fffb8004da0 exited after QThreadStorage 7 destroyed
Should I be worried about these messages? Do they, specially the second 1, mean any memory mismanagement?
Thanks
The code you've posted makes no sense. QThread
is not dynamically allocated so you cannot delete
it: the deleteLater
call will crash. Probably it never gets executed, since you show no code that would stop the thread anyway. There's also no point in destroying the thread after the camera has been destroyed.
The simplest way to do things safely would be to hold the camera and thread by value in your class, and declare them in proper order so that the thread is destroyed before the camera. At that point, the camera becomes threadless and will be safe to destroy in any thread.
There's also a nicer way to invoke methods in remote threads than using invokeMethod
:
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject*parent = 0): QThread(parent) {}
~Thread() { quit(); wait(); }
};
// See http://stackoverflow.com/a/21653558/1329652 for details about invoke.
template <typename F> void invoke(QObject * obj, F && fun) {
if (obj->thread == QThread::currentThread())
return fun();
QObject src;
QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun));
}
class MyObject : public QObject {
Q_OBJECT
AxisNetworkCamera camera;
Thread camThread { this };
Q_SLOT void updateImage(const QImage &);
Q_SLOT void cameraDisconnected();
public:
MyObject(QObject * parent = 0) : QObject(parent)
{
connect(&camera, &AxisNetworkCamera::imageUpdate, this, &MyObject::updateImage);
connect(&camera, &AxisNetworkCamera::cameraDisconnected, this, &MyObject::cameraDisconnected);
camera.moveToThread(&camThread);
camThread.start();
}
void startCamera(const QString & streamUrl) {
invoke(&camera, [=]{ camera.deviceStartup(streamUrl); });
}
};