在用moveThread时,本意是想避免主界面卡死,把运行时间久的放到子线程里去执行。结果运行时碰到一直崩溃的问题。
实例如下:
extern QProcessControl *g_pProcessCtrl;
#define SAFE_DELETE(e) if(e!= nullptr){delete e; e=nullptr;}
QDlgMain::QDlgMain(QWidget *parent)
: QMainWindow(parent)
{
m_ui.setupUi(this);
g_pProcessCtrl = new QProcessControl();
m_pThread = new QThread();
g_pProcessCtrl->moveToThread(m_pThread);
m_pThread->start();
}
QDlgMain::~QDlgMain()
{
m_pThread->quit();
m_pThread->wait();
SAFE_DELETE(g_pProcessCtrl);
}
QProcessControl::QProcessControl(QObject *parent)
: QObject(parent)
{
m_pMotion = new MotionControl();
for (int i = 0; i < StationID_MAX;i++)
{
m_pDev[i] = new DeviceControl(m_pMotion,eStationID(i),this);
}
}
QProcessControl::~QProcessControl()
{
for (int i = 0; i < StationID_MAX;i++)
{
SAFE_DELETE(m_pDev[i]);
}
SAFE_DELETE(m_pMotion);
}
原本以为这种写法没问题,结果一运行,QProcessControl析构函数一直崩溃。
报错截图如下:
报错内容为 不能通过不同的线程来发送对象,创建的对象和析构的对象不在同一个线程里。
经查找资料发现这个问题的本质在于,构造函数在主线程创建,析构函数我也是写在主线程里,但此时对象已经被移到子线程里,主线程这里再来析构函数,就行不通了。
Qt说明书里有一段话:
如果目标线程为零,那么这个对象及其子对象的所有事件处理都停止了。个人认为应该是要把线程指针析构掉置为null,此时构造的对象就可以在主线程中析构掉。 只需要在safedelete(g_processcontrol)前 加上一句 safedelete(m_pThread),运行正常。
QDlgMain::~QDlgMain()
{
m_pThread->quit();
m_pThread->wait();
SAFE_DELETE(m_pThread); //加上这句话
SAFE_DELETE(g_pProcessCtrl);
Sleep(100);
}
这是第一种方案:主线程创建的对象,在主线程中析构。
第二种解决方案:主线程创建对象,子线程中析构。
QDlgMain::QDlgMain(QWidget *parent)
: QMainWindow(parent)
{
m_ui.setupUi(this);
g_pProcessCtrl = new QProcessControl();
m_pThread = new QThread();
g_pProcessCtrl->moveToThread(m_pThread);
m_pThread->start();
//这句至关重要
connect(m_pThread, &QThread::finished, g_pProcessCtrl, &QObject::deleteLater);
}
QDlgMain::~QDlgMain()
{
m_pThread->quit();
m_pThread->wait();
//SAFE_DELETE(g_pProcessCtrl); 由于已经在子线程中析构,所以这里不能再写了
}
可以在构造函数及析构函数里添加获取线程ID,能看出第一种都是在主线程中析构,第二种构造函数的线程ID和析构函数ID是不一样。