如何在Qt中发出跨线程信号?

2021-12-09 00:00:00 qt signals-slots qt-signals c++

Qt 文档声明信号和槽可以directqueuedauto.

Qt documentation states that signals and slots can be direct, queued and auto.

它还指出,如果拥有插槽的对象生活"在与拥有信号的对象不同的线程中,则发出此类信号就像发布消息一样 - 信号发射将立即返回,并且将在目标线程的事件循环中调用插槽方法.

It also stated that if object that owns slot 'lives' in a thread different from object that owns signal, emitting such signal will be like posting message - signal emit will return instantly and slot method will be called in target thread's event loop.

不幸的是,文档没有指明lives"代表什么,也没有可用的示例.我尝试了以下代码:

Unfortunately, documentation do not specify that 'lives' stands for and no examples is available. I have tried the following code:

main.h:

class CThread1 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        msleep( 200 );
        std::cout << "thread 1 started" << std::endl;
        MySignal();
        exec();
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

main.cpp:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & oThread2, SLOT( MySlot() ) );
    oThread1.start();
    oThread2.start();
    oThread1.wait();
    oThread2.wait();
    return a.exec();
}

输出为:

thread 2 started
thread 1 started

MySlot() 永远不会被调用 :(.我做错了什么?

MySlot() is never called :(. What I'm doing wrong?

推荐答案

你的代码有不少问题:

  • 就像 Evan 所说的那样,缺少 emit 关键字
  • 您所有的对象都存在于主线程中,只有 run 方法中的代码存在于其他线程中,这意味着将在主线程中调用 MySlot 插槽,我不确定这是否是您想要的
  • 你的槽永远不会被调用,因为主事件循环永远不会被启动:你对 wait() 的两次调用只会在很长时间后超时(你可能会在这之前杀死你的应用程序),我不也不要认为那是您想要的,无论如何它们在您的代码中确实没有用处.

这段代码很可能会起作用(虽然我还没有测试过),而且我认为它可以完成您想要它做的事情:

This code would most likely work (though I have not tested it) and I think it does what you want it to do :

class MyObject : public QObject
{
    Q_OBJECT
public slots:
    void MySlot( void )
    {
        std::cout << "slot called" << std::endl;
    }
};

class CThread1 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 1 started" << std::endl;
        int i = 0;
        while(1)
        {
           msleep( 200 );
           i++;
           if(i==1000)
              emit MySignal();
        }
    }
signals:
    void MySignal( void );
};

class CThread2 : public QThread
{
    Q_OBJECT
public:
    void run( void )
    {
        std::cout << "thread 2 started" << std::endl;
        exec();
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    CThread1 oThread1;
    CThread2 oThread2;
    MyObject myObject;
    QObject::connect( & oThread1, SIGNAL( MySignal() ),
        & myObject, SLOT( MySlot() ) );
    oThread2.start();
    myObject.moveToThread(&oThread2)
    oThread1.start();
    return a.exec();
}

现在 MyObject 将存在于 thread2 中(感谢 moveToThread).

Now MyObject will live in thread2 (thanks to moveToThread).

MySignal 应该从 thread1 发送(我不确定那个,它可能是从主线程发送的,这并不重要).

MySignal should be sent from thread1 (thought I'm not sure on that one, it might be sent from main thread, it doesn't really matter).

线程 1 中不需要事件循环,因为发出信号不需要事件循环.线程 2 中需要一个事件循环(由 exec() 启动)来接收信号.

No event loop is needed in thread1 since emitting a signal doesn't need an event loop. An event loop is needed in thread2 (lanched by exec()) to receive the signal.

MySlot 将在线程 2 中调用.

MySlot will be called in thread2.

相关文章