您的位置:首页 > 移动开发 > Objective-C

Qt多线程间信号槽传递非QObject类型对象的参数

2015-12-02 09:56 661 查看
     多线程间需要传递信号给另外一个线程的槽,而信号和槽所使用的参数为非QObject,无论其是stl的标准库类型还是其他类型,都必须先注册,否则信号发送了,槽将会始终不调用。也就是说qt的槽参数一定要是QOject类型的参数(QObject类的子类型也是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 * sender, const char * signal, const QObject * receiver, const char * method,Qt::ConnectionType type =
Qt::AutoConnection )


Qt支持6种连接方式,其中3中最主要:
Qt::DirectConnection(直连方式)

      当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行)
Qt::QueuedConnection(排队方式)

      当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)
Qt::AutoConnection(自动方式)

      Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。

      我的项目中的确跨线程使用了ERROR_LEVEL为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用ERROR_LEVEL类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:

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 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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: