有两个类:Widget
和Worker
。这是一个示意图代码。
class Widget
{
Worker *m_worker;
QTextEdit *m_edit;
public:
Widget():m_edit(new QTextEdit){}
~Widget()
{
m_worker->ShouldStop = true;
delete *m_worker;
}
void doWork()
{
m_worker = new Worker;
if (!worker->doWork())
m_edit->setText("failed");
}
}
class Worker
{
Worker() : ShouldStop(false){}
public:
bool ShouldStop;
bool doWork()
{
while(true && !ShouldStop)
{
QThread::sleep(1);
QApplication::processEvents();
}
//consider the work undone if a stop was forced
if (ShouldStop)
return false;
}
}
在调用doWork()
的Widget
之后,在Worker
的方法doWork()
中执行循环。然后关闭一个小部件,并在对processEvents()
的一个调用中调用其析构函数。然后执行返回到doWork()
的Worker
。它现在检查ShouldStop
并返回到Widget
的doWork()
,并尝试向m_edit
添加一些内容。但是,Widget
对象已经死了。
问题:
发布于 2013-03-05 18:26:20
理想情况下,工作线程应该通过信号和插槽机制返回数据,而不是直接访问原始对象。实际上,创建一个线程并避免调用QApplication::processEvents()
是避免问题的第一种方法。
此外,当您想要在一个新线程中启动一个工作人员时,您应该考虑使用这样的设计。与其子类QThread,您只需创建一个通用QThread并将一个QObject分配给它,如下所示:
Worker *worker = new Worker;
QThread *workerThread = new QThread(this);
connect(workerThread, &QThread::started, worker, &Worker::doWork);
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
worker->moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started()
workerThread->start();
如果您使用的是Qt 5,请考虑按照此模式重新构造代码。
发布于 2013-03-06 01:47:44
@Alex绝对是q2的最佳选择。他只是忘了提到如何继续删除(q1)。假设Widget
创建了对象workerThread
,那么这是必要的:
~Widget(){
if(workerThread->isRunning()){
workerThread->terminate(); <--- this line, right there
workerThread->wait():
}
...
}
为什么?因为删除QThread
只需删除线程对象但是不会阻止线程运行,并且可能会使应用程序崩溃。。注意,如果您正在使用
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
正如亚历克斯所提到的,那么在调用worker
之后访问terminate
是不安全的,因为它将触发finished()
信号,执行worker->deleteLater
,并最终删除worker
。
发布于 2013-03-05 15:42:28
您可以让Widget使用信号通知Widget的所有者启动Widget的工人。
所有者同时拥有Widget和Worker。小部件告诉所有者某些东西是被触发的,并且Owner负责确定Worker的doWork()是正确的响应,并管理Worker和Widget的生存期。工人和Widget彼此不了解,但是所有者可能会将他们的一些信号和插槽连接在一起。
https://stackoverflow.com/questions/15236223
复制相似问题