使用 QThread 时类型转换和 QThreadStorage 警告?
Type conversion and QThreadStorage warning while using QThread?
我刚开始使用 QThread
。我正在使用 QThread
从 Axis IP 摄像机抓取图像。在以下代码片段中,我将相机 class 移动到新线程:
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);
我正在调用启动相机的函数:
QMetaObject::invokeMethod(camera, "deviceStartup", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(streamUrl)));
应用程序运行良好,当我关闭它时也能正常关闭,但我担心的是一些警告消息。
第一个是我启动相机的时候:
Type conversion already registered from type QPair<QByteArray,QByteArray> to type QtMetaTypePrivate::QPairVariantInterfaceImpl
第二个是当我关闭应用程序时:
QThreadStorage: Thread 0x7fffb8004da0 exited after QThreadStorage 7 destroyed
我应该担心这些消息吗?它们,特别是第二个 1,是否意味着任何内存管理不善?
谢谢
您发布的代码毫无意义。 QThread
不是动态分配的,因此您不能 delete
它:deleteLater
调用会崩溃。可能它永远不会被执行,因为您没有显示无论如何都会停止线程的代码。也没有必要在相机被销毁后销毁线程。
安全地做事的最简单方法是在您的 class 中按值保存相机和线程,并以正确的顺序声明它们,以便线程在相机之前被销毁。届时,相机将变为无线程,并且可以安全地在任何线程中销毁。
还有一种比使用 invokeMethod
:
在远程线程中调用方法更好的方法
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject*parent = 0): QThread(parent) {}
~Thread() { quit(); wait(); }
};
// See 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); });
}
};
我刚开始使用 QThread
。我正在使用 QThread
从 Axis IP 摄像机抓取图像。在以下代码片段中,我将相机 class 移动到新线程:
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);
我正在调用启动相机的函数:
QMetaObject::invokeMethod(camera, "deviceStartup", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(streamUrl)));
应用程序运行良好,当我关闭它时也能正常关闭,但我担心的是一些警告消息。
第一个是我启动相机的时候:
Type conversion already registered from type QPair<QByteArray,QByteArray> to type QtMetaTypePrivate::QPairVariantInterfaceImpl
第二个是当我关闭应用程序时:
QThreadStorage: Thread 0x7fffb8004da0 exited after QThreadStorage 7 destroyed
我应该担心这些消息吗?它们,特别是第二个 1,是否意味着任何内存管理不善?
谢谢
您发布的代码毫无意义。 QThread
不是动态分配的,因此您不能 delete
它:deleteLater
调用会崩溃。可能它永远不会被执行,因为您没有显示无论如何都会停止线程的代码。也没有必要在相机被销毁后销毁线程。
安全地做事的最简单方法是在您的 class 中按值保存相机和线程,并以正确的顺序声明它们,以便线程在相机之前被销毁。届时,相机将变为无线程,并且可以安全地在任何线程中销毁。
还有一种比使用 invokeMethod
:
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject*parent = 0): QThread(parent) {}
~Thread() { quit(); wait(); }
};
// See 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); });
}
};