c++ - 多线程应用程序中的槽执行策略

标签 c++ multithreading qt signals-slots

我有两个线程继承自 QThread。该场景是 thread2 的对象发出信号,而 thread1 的对象有一个要执行的槽。我希望插槽在 thread2 中执行,但它在主线程中执行!!!。这是我的示例代码来表明:

头文件.h

class Thread1 : public QThread{
    Q_OBJECT
public:
    Thread1(){}
protected:
    void run(){
        qDebug() << "run in thread " << this->currentThreadId();
        exec();
    }
private slots:
    void slot1(){
        qDebug() << "slot in " << this->currentThreadId();
    }

signals:
    void sig1();
};
class Thread2 : public QThread{
    Q_OBJECT
protected:
    void run(){
        msleep(100);
        qDebug() << "emit sig2 in: " << this->currentThreadId();
        emit sig2();
    }
signals:
    void sig2();
};

class obj1 : public QObject {
    Q_OBJECT
public:
    obj1(){
        connect(&t2, SIGNAL(sig2()), &t1, SLOT(slot1()));
        connect(this, SIGNAL(sigObj()), &t1, SLOT(slot1()));
        t1.start();
        t2.start();
    }
public:
    void fcn(){
        QThread::msleep(1000);
        emit sigObj();
        qDebug() << "emit sigObj in " << QThread::currentThreadId();
    }
private:
    Thread1 t1;
    Thread2 t2;


signals:
    void sigObj();
};

main.cpp

QCoreApplication a(argc, argv);
obj1 o1;
o1.fcn();

return a.exec();

我对这段代码的期望是 slot1() 始终在线程 1 中从发出的信号 sig2() 和 sigObj() 中执行。但是无论我们在哪个线程中发出信号,slot1 都在主线程中执行。顺便说一句,这是我的输出:

run in thread  0x7ffff6169700  (thread1)
emit sig2 in:  0x7ffff5968700  (thread2)
slot in  0x7ffff7fce740        (main thread)
emit sigObj in  0x7ffff7fce740 (main thread)
slot in  0x7ffff7fce740        (main thread)

是出了什么问题还是总是这样?还有如果我想在自己的线程中执行槽怎么办?

最佳答案

QThread 没有什么特别之处。它只是一个 QObject碰巧 也是平台本地线程的句柄。但是 QThread 派生对象的插槽就像您有一个普通的 QObject 一样工作。它们将在对象的线程中执行——这将是您执行对象构造函数的线程,或者在您的情况下是主线程。这就是令人困惑的地方:您的任何一个线程对象的 thread() 仍然是主线程,这就是槽将运行的地方。仅仅因为您的 QObject 被称为 QThread 并不会使它有任何不同。

修复很简单:不要覆盖QThread 的“运行”,也不要向QThread 添加功能。相反,明确地将您的对象移动到您希望它们完成工作的线程。在 QThread 上显式调用 moveToThread 是一种反模式,因此不要将其作为“快速破解”。

在这种情况下,派生自 QThread 的唯一原因是通过添加 quit(); 将其转换为适当的 RAII 类; wait(); 到它的析构函数。

这是您的代码的外观,已修复:

// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-sigslot-37325348
#include <QtCore>

class Worker1 : public QObject {
   Q_OBJECT
public:
   Q_SIGNAL void sig1();
   Q_SLOT void slot1() {
      qDebug() << "slot in" << thread();
   }
};

class Worker2 : public QObject {
   Q_OBJECT
public:
   Worker2() {
      QTimer::singleShot(100, this, [this]{
         qDebug() << "emit sig2 in" << thread();
         emit sig2();
      });
   }
   Q_SIGNAL void sig2();
};

class Object : public QObject {
   Q_OBJECT
   Worker1 w1;
   Worker2 w2;
   QThread t1, t2;
   Q_SIGNAL void sig();
public:
   Object() {
      t1.setObjectName("t1");
      t2.setObjectName("t2");
      connect(&w2, &Worker2::sig2, &w1, &Worker1::slot1);
      connect(this, &Object::sig, &w1, &Worker1::slot1);
      w1.moveToThread(&t1);
      w2.moveToThread(&t2);
      t1.start();
      t2.start();
      QTimer::singleShot(1000, this, [this]{
         qDebug() << "emit sig in" << thread();
         emit sig();
      });
   }
   ~Object() { t1.quit(); t2.quit(); t1.wait(); t2.wait(); }
};

int main(int argc, char ** argv) {
   QCoreApplication app{argc, argv};
   app.thread()->setObjectName("main_thread");
   Object obj;
   QTimer::singleShot(2000, &app, [&]{ app.quit(); });
   return app.exec();
}

#include "main.moc"

输出:

emit sig2 in QThread(0x7fff4fd98bd0, name = "t2")
slot in QThread(0x7fff4fd98bc0, name = "t1")
emit sig in QThread(0x7fe3dac0aed0, name = "main_thread")
slot in QThread(0x7fff4fd98bc0, name = "t1")

关于c++ - 多线程应用程序中的槽执行策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37325348/

相关文章:

c++ - qt 创建 gst-launch 进程

linux - Qt Creator CONFIG(调试、发布)开关不起作用

c++ - 解析csv文件c++

c++ - Eclipse CDT Luna 未跟踪的 header

c++ - 层次结构中的反向可变参数模板参数

c++ - 使用默认值或使用 setValue 创建构造函数

c - 使用#pragma omp 进行硬并行化以找到第 N 个素数

python - “self”未定义 - 使用计时器进行线程处理

java - 并发读取共享对象中的只读字段并写入读/写字段

python - 如何使用 Qt 将一个 Widget 替换为另一个?