QT的元类型和QT线程通信的方法
2011-01-02 15:17
399 查看
今天调试QT线程通信的程序时,突然发现如下消息:
其中PEOPLE只是我定义的枚举类型即enum PEOPLE。然后在Qt的信号-槽函数的参数中使用了这个枚举型,在发送信号时就出现了上述警告。上面警告的大概意思是信号队列中无法使用PEOPLE类型,要使用qRegisterMetaType()注册该类型后方可使用。
通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:
Qt支持6种连接方式,其中3中最主要:
Qt::DirectConnection(直连方式)
当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行)
Qt::QueuedConnection(排队方式)
当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)
Qt::AutoConnection(自动方式)
Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。
我的项目中的确跨线程使用了PEOPLE为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用PEOPLE类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);
这样做的确能使警告信息消失,因为Qt官方文档写了:
With queued connections, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes.
即使用排队方式的信号-槽机制,Qt的元对象系统(meta-object system)必须知道信号传递的参数类型。这里手动改为直连方式,Qt的元对象系统就不必知道参数类型了,于是警告信息消失。但这样做是不安全的,见Qt官方文档:
Be aware that using direct connections when the sender and receiver live in different threads is unsafe if
an event loop is running in the receiver's thread, for the same reason that calling any function on an obje
ct living in another thread is unsafe.
因此,咱还是老老实实地用qRegisterMetaType()注册类型吧
我写的线程通讯方法是采用信号槽机制,通常情况下,信号和槽机制可以同步操作,这就意味着在发射信号的时候,使用直接函数即可以立刻调用连接到一个信号上的多个槽。然而,当连接位于不同线程中的对象时,这一机制就会变得不同步起来,可以通过刚才介绍的,修改QObject::connect()的第5个可选参数而改变。
connect的第五个参数Qt::QueuedConnection表示槽函数由接受信号的线程所执行,如果不加表示槽函数由发出信号的次线程执行。当传递信号的参数类型不是QT的元类型时要先注册,关于QT的元类型可以参看QT文档。
QMetaType这个类里面列举了所有的元类型。
以枚举PEOPLE为例,注册时首先Q_DECLARE_METATYPE(PEOPLE);
然后,int id=qRegisterMetaType<PEOPLE>("PEOPLE");
加上这两句就注册成功了。
贴个示例的代码,次线程不断更改一个PEOPLE{boy,girl}的信息传给GUI主线程,主线程在GUI界面上显示。
mythread.h
mainwindow.h
mythread.cpp
mainwindow.cpp
元类型注册方法受益于这篇文章
其中PEOPLE只是我定义的枚举类型即enum PEOPLE。然后在Qt的信号-槽函数的参数中使用了这个枚举型,在发送信号时就出现了上述警告。上面警告的大概意思是信号队列中无法使用PEOPLE类型,要使用qRegisterMetaType()注册该类型后方可使用。
通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:
Qt支持6种连接方式,其中3中最主要:
Qt::DirectConnection(直连方式)
当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行)
Qt::QueuedConnection(排队方式)
当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)
Qt::AutoConnection(自动方式)
Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。
我的项目中的确跨线程使用了PEOPLE为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用PEOPLE类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);
这样做的确能使警告信息消失,因为Qt官方文档写了:
With queued connections, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes.
即使用排队方式的信号-槽机制,Qt的元对象系统(meta-object system)必须知道信号传递的参数类型。这里手动改为直连方式,Qt的元对象系统就不必知道参数类型了,于是警告信息消失。但这样做是不安全的,见Qt官方文档:
Be aware that using direct connections when the sender and receiver live in different threads is unsafe if
an event loop is running in the receiver's thread, for the same reason that calling any function on an obje
ct living in another thread is unsafe.
因此,咱还是老老实实地用qRegisterMetaType()注册类型吧
我写的线程通讯方法是采用信号槽机制,通常情况下,信号和槽机制可以同步操作,这就意味着在发射信号的时候,使用直接函数即可以立刻调用连接到一个信号上的多个槽。然而,当连接位于不同线程中的对象时,这一机制就会变得不同步起来,可以通过刚才介绍的,修改QObject::connect()的第5个可选参数而改变。
connect的第五个参数Qt::QueuedConnection表示槽函数由接受信号的线程所执行,如果不加表示槽函数由发出信号的次线程执行。当传递信号的参数类型不是QT的元类型时要先注册,关于QT的元类型可以参看QT文档。
QMetaType这个类里面列举了所有的元类型。
以枚举PEOPLE为例,注册时首先Q_DECLARE_METATYPE(PEOPLE);
然后,int id=qRegisterMetaType<PEOPLE>("PEOPLE");
加上这两句就注册成功了。
贴个示例的代码,次线程不断更改一个PEOPLE{boy,girl}的信息传给GUI主线程,主线程在GUI界面上显示。
mythread.h
#ifndef MYTHREAD_H #define MYTHREAD_H #include <QThread> enum PEOPLE{boy,girl}; class MyThread : public QThread { Q_OBJECT public: MyThread(); ~MyThread(); protected: void run(); signals: void changeText(PEOPLE pe); }; #endif // MYTHREAD_H
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include "mythread.h" #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void labelSetText(PEOPLE qstr); protected: void changeEvent(QEvent *e); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
mythread.cpp
#include "mythread.h" MyThread::MyThread() : QThread() { } MyThread::~MyThread() { } void MyThread::run(){ static int i=1; while(true) { if(i==1)emit changeText(boy); else emit changeText(girl); i=i*(-1); QThread::sleep(1); } }
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include "mythread.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); MyThread *mythread = new MyThread; int id=qRegisterMetaType<PEOPLE>("PEOPLE"); connect(mythread,SIGNAL(changeText(PEOPLE)),this,SLOT(labelSetText(PEOPLE)),Qt::QueuedConnection); mythread->start(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::changeEvent(QEvent *e) { QMainWindow::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); break; default: break; } } void MainWindow::labelSetText(PEOPLE qstr){ switch(qstr) { case boy: ui->label->setText("BOY");break; case girl: ui->label->setText("GIRL");break; } }
元类型注册方法受益于这篇文章
相关文章推荐
- QT的元类型和QT线程通信的方法
- QT的元类型和QT线程通信的方法
- QT的元类型和QT线程通信的方法
- 进程线程通信方法总结
- QT---线程间通信
- 线程间通信的三种方法
- QT小例子GUI(主)线程与子线程之间的通信
- 线程间通信的三种方法
- 多线程(线程间通信-多生产者多消费者问题-JDK1.5解决办法-范例),停止线程,线程中方法的区别,匿名内部类实现多线程,线程总结
- 多线程编程之重点--使用DSP/BIOS时选择线程类型的参考方法
- Qt新建线程的方法
- Qt5线程之间通信的小例子
- Java多线程通信-利用传统的线程通信wait(),notify()方法实现“生产者消费者模式”
- 多线程编程-线程间通信-join方法的使用(六)
- 【原】qt4 子线程给主线程发消息,发数据,通信,qthread gui postevent emit
- 浅析线程间通信三:Barriers、信号量(semaphores)以及各种同步方法比较
- 线程间通信的三种方法
- qt4 子线程给主线程发消息,发数据,通信,qthread gui postevent emit
- QT GUI(主)线程与子线程之间的通信——使用跨线程的信号槽
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制