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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/638251/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:25:59  来源:igfitidea点击:

How to emit cross-thread signal in Qt?

c++qtsignals-slotsqt-signals

提问by grigoryvp

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

Qt 文档指出信号和槽可以是direct,queuedauto

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:

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:

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()从来没有被称为:(。我做错了什么?

采纳答案by Aiua

There are quite a few problems with your code :

您的代码有很多问题:

  • like said by Evan the emit keyword is missing
  • 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
  • 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.
  • 就像 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();
}

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. An event loop is needed in thread2 (lanched by exec()) to receive the signal.

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

MySlot will be called in thread2.

MySlot 将在 thread2 中调用。

回答by Will Bickford

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 notsubclass 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 方法。

回答by kuake56

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

您可以在此信号中添加多个参数