Qt多线程间信号槽传递⾮QObject类型对象的参数
多线程间需要传递信号给另外⼀个线程的槽,⽽信号和槽所使⽤的参数为⾮QObject,⽆论其是stl的标准库类型还是其他类型,都必须先注册,否则信号发送了,槽将会始终不调⽤。也就是说qt的槽参数⼀定要是QOject类型的参数(Q的⼦类型也是QObject类型)
注册⽅式如下:
#include <QMetaType> //该⽂件为qRegisterMetaType所在头⽂件,也可以使⽤ #include <QtGui>此头⽂件包括了所有的qt类型头⽂件
qRegisterMetaType<type>("type");
退宿申请如我需要传递⼀个stl的map类型,则需在连接信号和槽之前先注册这个map类型
垃圾收集点qRegisterMetaType<std::map<std::string,AppInfo>>("std::map<std::string,AppInfo>"); //AppInfo为⾃定义的⼀个类型
connect(cfThread,SIGNAL(SetInfo(const map<string,AppInfo>&)),this,SLOT(ShowConfig(const map<string,AppInfo>&));
也可以⽤以下这种⽅法,不过此法不安全,
使⽤connect的第5个参数,将默认的Qt::AutoConnection改为Qt::DirectConnection,也能成功调⽤槽函数。但是此法不安全。
通常使⽤的connect,实际上最后⼀个参数使⽤的是Qt::AutoConnection类型:
bool QObject::connect ( const QObject * nder, const char * signal, const QObject * receiver, const char * method, type = Qt::AutoConnection )
Qt⽀持6种连接⽅式,其中3中最主要:
Qt::DirectConnection(直连⽅式)
当信号发出后,相应的槽函数将⽴即被调⽤。emit语句后的代码将在所有槽函数执⾏完毕后被执⾏。(信号与槽函数关系类似于函数调⽤,同步执⾏)
Qt::QueuedConnection(排队⽅式)
当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,
调⽤相应的槽函数。emit语句后的代码将在发出信号后⽴即被执⾏,⽆需等待槽函数执⾏完毕。(此时信号被塞到信号队列⾥了,信号与槽函数关系类似于消息通信,异步执⾏)
适合的近义词Qt::AutoConnection(⾃动⽅式)
财务助理工作内容Qt的默认连接⽅式,如果信号的发出和接收这个信号的对象同属⼀个线程,那个⼯作⽅式与直连⽅式相同;否则⼯作⽅式与排队⽅式相同。
我的项⽬中的确跨线程使⽤了ERROR_LEVEL为参数类型的信号,因此使⽤的应当是排队⽅式的信号-槽机制,出现“队列中⽆法使⽤ERROR_LEVEL类型”的警告信息就可以理解了。放狗搜了⼀圈,提供了个这样的解决⽅案:
魔方怎么拼六面connect(cm, SIGNAL(ndLog(QUuid, QByteArray, bool)),
this,SLOT(ndRes(QUuid,QByteArray,bool)));
独立近义词窗外城改为:
connect(cm, SIGNAL(ndLog(QUuid, QByteArray, bool)),
this,SLOT(ndRes(QUuid,QByteArray,bool)), Qt::DirectConnection);
这样做的确能使警告信息消失,因为Qt官⽅⽂档写了:
With queued connections, the parameters must be of types that are known to Qt's meta-object system, becau 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 nder 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 object living in another thread is unsafe.
解决⽅法有两种:
英语投诉信⼀、把⾃⼰定义的类型注册为元组类型,使⽤qRegisterMetaType()注册,可以把这个函数放在connect()函数使⽤之前。
参考代码:
1 #include <QMetaType>//记得包含这个头⽂件
2//my_type是我⾃⼰定义的类型
3 qRegisterMetaType<my_type>("my_type");
4 connect(xx,SIGNAL(xx(my_type)),xx,SLOT(xx(my_type)));
⼆、在connect函数的第五个参数加⼊Qt::DirectConnection
1 connect(xx,SIGNAL(xx(my_type)),xx,SLOT(xx(my_type)),Qt::DirectConnection);