QThread:如果没有实现run(),它在等待信号时会做什么?

时间:2014-04-17 12:39:03

标签: c++ multithreading qt

首先,我没有使用GUI。 (如果重要的话。)我想将文件的路径发送到一个线程(如char*),让它处理文件,然后返回。最好,我希望线程在不使用时停止。

Qt文档显示了两种创建线程的方法:

  1. 创建QObjectmoveToThread()

  2. 在需要时创建QThread然后start()

  3. 在上述两种方法中,如果我没有run()功能,会发生什么?我没有,因为我没有看到将char*传递给run()的方法,所以我正在使用信号。我必须start()线程才能正常工作吗?如果是这样,如果没有run(),这会怎么做?我可以创建它,连接信号/插槽,然后在需要时调用它吗?在这种情况下,上述方法之一是否有优势?

    更新:感谢您快速回复Johannes Schaub和thuga。

    1. 如果我正在使用QObject->moveToThread(),那么该线程是否在事件循环中运行?当没有输入时,这个事件循环会休眠吗? (如果是这样,那很好。)线程(事件循环)与QObject的信号和插槽相关联,对吧?所以我需要通过将它放在构造函数中将此对象的范围作为调用线程? (并且析构函数中有quit() wait())它因此在原始线程的整个生命周期内运行?

    2. 我认为我不需要为QThread设置一个插槽,因为我只想调用它,而不是来回通信。 (除了完成的信号。)所以我会做这样的事情:

      一个。创建QThread的实例:

      WorkerThread *workerThread = new WorkerThread(this);
      

      湾发送字符串。这是我不确定的部分。我想约翰内斯试图解释,但我还不清楚。我无法通过信号/插槽发送文件名,因为QThread s不应使用插槽。 (但由于排队连接,可以在moveToThread()情况下)

      ℃。使用.start()

    3. 启动主题

3 个答案:

答案 0 :(得分:3)

默认运行函数然后调用exec,它进入事件循环。如果循环没有要处理的事件,则循环休眠。

移动到该线程的对象 QThread对象本身。这是另一个目标。 QThread对象本身只有事件循环,仍然与主线程关联(它的亲和力是主线程)。

如果线程在后台运行,最好使用QString作为文件名,然后调用相应的“processFile”函数或传递文件名的对象。调用可以通过信号槽连接或显式QMetaObject :: invokeMethod,使用连接类型QueuedConnection(将事件传递到对象线程的事件循环中,因此您的文件名通过包含在其中自动排队内部插槽调用事件)。

答案 1 :(得分:2)

  

如果我使用QObject->moveToThread(),那么该线程是否在事件循环中运行?

那些完全不相关。只要您QThreadstart()只会运行事件循环。为此,您不需要将任何物体移动到它上面。当然事件循环处于休眠状态,因为它没有传入的事件要处理 - 所以线程尽管已经启动,但不会占用任何CPU。

  

线程(事件循环)与QObject的信号和插槽相关联,对吗?

信号和插槽只是您可以链接的功能呼叫源和接收器。它们与事件循环没什么关系。

当发送方和接收方对象驻留在不同的线程中时,通过将QMetaCallEvent发布到对象的事件队列来实现插槽调用的传递。即使像所有事件一样,它也会被赋予QObject::event(QEvent*)方法。该方法作用于QMetaCallEvent并执行槽调用。

  

所以我需要将这个Object的作用域放在构造函数中作为调用线程吗? (并在析构函数中退出()wait())因此它在原始线程的整个生命周期内运行?

对象的生命周期与线程的生命周期分离。移动到给定线程的对象只能从该线程中被破坏。如果线程首先终止,则该对象变为无线程(其thread()返回nullptr),并且它可以从任何线程中被破坏,或者移动到另一个线程。无线程对象无法接收任何事件,但当然它可以接收直接的插槽调用。排队的老虎机呼叫不会起作用,因为它们最初作为事件传递,并且只在内部转换为呼叫。

  

我认为我不需要为QThread设置一个插槽,因为我只想调用它,而不是来回通信。

QThread是一个线程控制器。没有理由将其子类化。几乎在所有情况下,您都可以使用已移至该主题的QObjectQtConcurrent::run

  

所以我会做这样的事情:[...]创建QThread的实例:[...]发送字符串。

您希望将字符串发送到线程中的对象,而不是线程本身。

这是一个小例子:

// main.cpp
#include <QThread>
#include <QCoreApplication>
#include <QDebug>

class Worker : public QObject {
public:
  Q_SLOT void say(const QString & str) { qDebug() << str; }
};

/// A thread that's safe to destruct at any time.
class Thread : public QThred {
  using QThread::run;
public:
  ~QThread() { quit(); wait(); }
};

int main(int argc, char ** argv) {
  QCoreApplication app(argc, argv);
  Worker worker;
  Thread thread;
  thread.start();
  worker.moveToThread(&thread);
  // Equivalent to invoking the say slot from a signal
  QMetaObject::invokeMethod(&worker, "say", Q_ARG(QString, "hello"));
  //
  QMetaObject::invokeMethod(&app, "quit");
  return app.exec();
}

#include "main.moc"

答案 2 :(得分:1)

听起来你的线程应该处理char*然后等待。如果是这种情况,那么您可以使用第三个选项,在单个线程中运行单个函数,然后使用QtConcurrent::run()退出

简单示例:

void workerFunction(QString const &data){
    // ...
}

void callingFunction(){

    // ....

    char *data = .....;

    QFuture<void> future = QtConcurrent::run(workerFunction, QString(data)); 

}

编辑: 如果您需要的功能多于单个线程函数,但不如QThread的完全成熟子类那么多,那么QRunnable / QThreadPool对也是一个方便的中间选项。< / p>