简体   繁体   English

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

[英]How to emit cross-thread signal in Qt?

Qt documentation states that signals and slots can be direct , queued and auto . Qt 文档指出信号和槽可以是directqueuedauto

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

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();
}

Output is:输出是:

thread 2 started
thread 1 started

MySlot() is never called :(. What I'm doing wrong? MySlot()永远不会被调用 :(。我做错了什么?

There are quite a few problems with your code :您的代码有很多问题:

  • like said by Evan the emit keyword is missing就像 Evan 所说的那样,缺少 emit 关键字
  • all your objects live in the main thread, only the code in the run methods live in other threads, which means that the MySlot slot would be called in the main thread and I'm not sure that's what you want您所有的对象都存在于主线程中,只有 run 方法中的代码存在于其他线程中,这意味着将在主线程中调用 MySlot 插槽,我不确定那是您想要的
  • your slot will never be called since the main event loop will never been launched : your two calls to wait() will only timeout after a very long time (and you'll probably kill your application before that happens) and I don't think that's what you want either, anyway they really have no use in your code.您的插槽永远不会被调用,因为主事件循环永远不会启动:您对 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();
}

Now MyObject will live in thread2 (thanks to moveToThread).现在 MyObject 将存在于 thread2 中(感谢 moveToThread)。

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). MySignal 应该从 thread1 发送(我不确定那个,它可能是从主线程发送的,这并不重要)。

No event loop is needed in thread1 since emitting a signal doesn't need an event loop. thread1 中不需要事件循环,因为发出信号不需要事件循环。 An event loop is needed in thread2 (lanched by exec()) to receive the signal.在线程 2(由 exec() 启动)中需要一个事件循环来接收信号。

MySlot will be called in thread2. MySlot 将在 thread2 中调用。

Do not subclass QThread for Qt 4.4+不要为 Qt 4.4+ 子类化 QThread

While Aiua's answer is good, I want to point out some issues with QThread and Qt 4.6 or 4.7.虽然 Aiua 的回答很好,但我想指出 QThread 和 Qt 4.6 或 4.7 的一些问题。

This article sums it up: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/本文总结: http : //blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/

Lack of Documentation on Qt's part Qt 方面缺乏文档

Unfortunately the problem stems from a lack of updates to documentation.不幸的是,问题源于缺乏对文档的更新。 Prior to Qt 4.4 QThread had no default run() implementation, which meant that you had to subclass QThread in order to use it.在 Qt 4.4 之前,QThread 没有默认的 run() 实现,这意味着您必须继承 QThread 才能使用它。

If you're using Qt 4.6 or 4.7 then you almost certainly should not subclass QThread.如果你正在使用Qt 4.6或者4.7,那么你几乎肯定应该继承的QThread。

Use moveToThread使用 moveToThread

The key to getting slots to execute in a worker thread is to use the moveToThread method as Aiua pointed out.正如 Aiua 指出的那样,让插槽在工作线程中执行的关键是使用 moveToThread 方法。

you should emit the signal to start your thread function like你应该发出信号来启动你的线程函数,比如

emit operateCut(examId,examName_examTemplate[examName].studentIdRec,examName_examTemplate[examName].choiceRecA,examName_examTemplate[examName].choiceRecB,examName_examTemplate[examName].objectRecA,examName_examTemplate[examName].objectRecB);

you can add more than one argument in this signal您可以在此信号中添加多个参数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM