【问题标题】:How to signal a slot in another thread in Qt如何在 Qt 中的另一个线程中发出插槽信号
【发布时间】:2016-06-29 17:57:25
【问题描述】:

我使用 Qt 编写了一个简单的信号槽应用程序。我想向另一个主线程用完的线程发送信号。

这是我的代码:

class Thread1 : public QThread
{
    Q_OBJECT


    void run()
    {
        exec();
    }
public:
    Thread1(QObject* parent);

public slots:
    void a()
    {
        qInfo()<<QThread::currentThreadId();
    }
};
class Object : public QObject
{
    Q_OBJECT
public:
    Object(){}
    void start()
    {
        qInfo()<<QThread::currentThreadId();
        Thread1* thread = new Thread1(this);
        connect(this,SIGNAL(a()),thread,SLOT(a()));
        thread->start();
        emit a();
    }

signals:
    void a();
};

但它会返回:

0x7f9851c988c0
0x7f9851c988c0

如何调用输出另一个 threadID 的信号?

【问题讨论】:

    标签: c++ multithreading qt signals-slots qthread


    【解决方案1】:

    你把它弄反了。 QThread 是线程句柄,而不是线程本身。如果你想在另一个线程中运行某些东西,它属于你移动到一个线程的普通QObject。您根本不需要从 QThread 派生!您也不应该将QThread 的基础QObject 移动到线程本身。您所做的是在线程本身中有一个线程句柄。线程一结束,句柄就会失效(QObject 带有一个空的thread())。

    首先,如果您只需要在工作线程中运行一些运行完成的代码(例如进行计算),请使用线程池和QtConcurrent 框架。它为您管理所有线程:

    #include <QtConcurrent>
    ...
    QThread::currentThread()->setObjectName("main");
    qDebug() << QThread::currentThread();
    QtConcurrent::run([]{ qDebug() << QThread::currentThread(); }
    

    如果你坚持自己控制线程的生命周期,你会做以下事情:

    #include <QtCore>
    struct Worker : QObject {
      Q_SLOT void aSlot() { 
        qDebug() << QThread::currentThread(); 
        QThread::currentThread()->quit();
      }
      Q_SIGNAL void aSignal();
      Q_OBJECT
    };
    
    int main(int argc, char ** argv) {
      QCoreApplication app{argc, argv};
      QThread::currentThread()->setObjectName("main");
      QThread thread;
      thread.setObjectName("thread");
      Worker a, b;
      b.moveToThread(&thread);
      thread.start();
      QObject::connect(&a, &Worker::aSignal, &b, &Worker::aSlot);
      emit a.aSignal(); // the signal is emitted from the main thread
      thread.wait();
    }
    

    最后,请注意QDebug 类在将指针传递给QObject 时知道如何输出对象的地址、类和名称(如果已设置)。因此,你不需要使用QThread::currentThreadId(),QThread::currentThread() 就足够了——而且你可以给线程命名,因为它们毕竟是QObjects。

    【讨论】:

    • 如果我有一个Worker c;,它被移动到第三个线程并且也连接到aSignal。然后发出信号将在工人 b 和 c 中运行方法 aSlot,每个工人都在自己的线程中。对吗?
    • @lanoxx 正确。
    【解决方案2】:

    实现Thread1 构造函数,如下所示:

    Thread1(QObject* parent) { moveToThread(this); }
    

    【讨论】:

    • 是的,它完成了工作。但它需要删除父级。
    • 为什么需要删除父级?
    • 打印出不能为有父对象调用moveToThread。
    • Parent 不需要删除,只需要删除父子关系。从文档中:“必须始终在创建父级的线程中创建 QObject 的子级。这意味着,除其他外,您不应将 QThread 对象(this)作为在线程(因为 QThread 对象本身是在另一个线程中创建的)。”参考:doc.qt.io/qt-5.7/threads-qobject.html
    • 这可行,但不是一个好主意,因为QThread 是一个线程句柄。从概念上讲,在受控资源中拥有资源句柄是倒退的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多