1

有两个类:WidgetWorker。这是一个示意图代码。

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执行循环之后。然后关闭一个小部件,并在其中一次调用期间调用它的析构函数。然后执行然后返回到. 它现在检查并返回的并尝试向. 但是对象已经死了。doWork()WorkerprocessEvents()doWork()WorkerShouldStopdoWork()Widgetm_editWidget

问题:

  1. 如何干净地删除 Worker?
  2. 避免这种相互作用的最佳设计是什么?
4

3 回答 3

3

理想情况下,工作线程应该只通过信号和槽机制返回数据,而不是直接访问原始对象。实际上创建一个线程并避免调用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-06T02:26:20.230 回答
2

@Alex 的回答绝对是 q2 的必经之路。他只是忘了提及如何进行删除(q1)。假设Widget创建了 object workerThread,那么这是必要的:

 ~Widget(){
   if(workerThread->isRunning()){
         workerThread->terminate(); <--- this line, right there
         workerThread->wait(): 
   }
 ...
 }

为什么?因为删除一个QThread只是删除线程对象但不会停止线程运行,并且可能会使应用程序崩溃。请注意,如果您正在使用

connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);

worker正如 Alex 所提到的,那么在调用 to 之后访问是不安全的terminate,因为它会触发finished()信号,执行worker->deleteLater,并最终删除worker

于 2013-03-06T09:47:44.887 回答
1

您可以让 Widget 使用信号通知 Widget 的所有者为 Widget 启动 Worker。

Owner 拥有 Widget 和 Worker。Widget 告诉 Owner 触发了某些事情,而 Owner 负责确定 Worker 的 doWork() 是正确的响应,并负责管理 Worker 和 Widget 的生命周期。Worker 和 Widget 互不了解,但 Owner 可能会将它们的一些信号和插槽连接在一起。

于 2013-03-05T23:42:28.860 回答