如何在Qt发出跨线程信号? [英] How to emit cross-thread signal in Qt?

查看:270
本文介绍了如何在Qt发出跨线程信号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Qt文档规定信号和槽可以直接排队 / code>。



它还表示,如果拥有槽的对象在线程中不同于拥有信号的对象,发出这样的信号将会像发布消息一样 - 信号emit将返回instant和slot方法将在目标线程的事件循环中调用。



不幸的是,文档没有指定生命代表,没有可用的例子。我试过下面的代码:



main.h:

  class CThread1:public QThread 
{
Q_OBJECT
public:
void run
{
msleep(200);
std :: cout<< 线程1开始< std :: endl;
MySignal();
exec();
}
信号:
void MySignal(void);
};

class CThread2:public QThread
{
Q_OBJECT
public:
void run(void)
{
std :: cout < 线程2开始< 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();
}

输出为:

 线程2已启动
线程1已启动

MySlot()从不调用:(。我做错了什么?

解决方案

您的代码有很多问题:




  • 就像Evan说的那样,emit关键字丢失了

  • 所有对象都在主线程中,只有运行方法中的代码存在于其他线程,这意味着MySlot插槽将在主线程中调用,我不确定这是你想要的

  • 您的插槽永远不会被调用,因为主事件循环将永远不会启动:您的两个调用wait()只会在很长时间后超时(并且你可能会杀了你的



这个代码很可能工作(虽然我没有测试它),我认为它是你想要它做的:

  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 < 线程1开始< std :: endl;
int i = 0;
while(1)
{
msleep(200);
i ++;
if(i == 1000)
emit MySignal();
}
}
信号:
void MySignal(void);
};

class CThread2:public QThread
{
Q_OBJECT
public:
void run(void)
{
std :: cout < 线程2开始< 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();
}


$ b $ p

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

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



thread1中不需要事件循环,因为发出信号不需要事件循环。在thread2中需要一个事件循环(由exec()调用)来接收信号。



MySlot将在thread2中调用。


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.

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?

解决方案

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.

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).

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).

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 will be called in thread2.

这篇关于如何在Qt发出跨线程信号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆