2
votes

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

1

1 Answers

2
votes

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); });
  }
};