信号和槽作为qt独有强大的无缝对象通讯机制模型, 是QT的核心特征。
(一)方法
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal ,const QObject *receiver, const QMetaMethod &method Qt::ConnectionType type = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, const char *signal,const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
(1)信号槽机制:信号槽用于两个对象之间的通信。编程逻辑中我们经常用到任何对象和其他对象进行数据通讯。比如我们做通讯的时候经常遇到数据接收和解析。我们希望数据接收和数据解析用于两个线程工作,提高效率,于是创建两个对象(一个数据接收类,一个数据解析类),这样我们就可通过信号emit(发射)将数据接收对象数据通知到数据解析对象中。函数如下:
connect(data_rev,&myTcpserver::decode_data,data_rev_analyse,&data_analyse::work_start);
(2)这里说一下多个信号和槽的应用过程。一个信号可以关联多个槽函数,多个信号也可以关联同一个槽上。当然也能信号关联到另一个信号上去。那么这里多个槽和信号关联后,当这个信号发射的时候槽会一个接一个的区执行,执行的顺序也是随机的(有网上说是和connect定义顺序有关我认为不准确)。这里无法指定他们的顺序的。
还有一个很重要的,信号槽关联的时候是互不干扰的,他们都占用各自的内存。这一片信号槽执行不会影响其他片信号槽的执行。这里同一线程如果一个槽函数执行进入阻塞不会影响其他槽函数。
(三)这里在说以下信号和槽的声明
声明一个信号要使用signals关键字,在signals前面是不能使用public/private/protected限定符的,因为只有定义该信号的类和子类才可以发射此信号。还有就是这个信号只能声明不能对它进行定义实现,信号没有返回值只能是void 类型。
声明一个槽函数需要用slots关键字,一个槽可以是public/private/protected类型,也可以是虚函数,因为槽函数和普通成员函数是一样的。当然你也可以调用槽函数,和普通成员函数一样的。他和普通成员函数唯一的区别就是他能被信号 关联。
(四)connect 最容易被轻视的一个参数 Qt::ConnectionType
在使用connect 函数时候最容易忽略最后一个参数 Qt::ConnectionType。这里参数表明了关联的方式,默认值是:Qt::AutoConnection。这里我把五个类型都列举以下。
类型 | 描述 |
AutoConnection |
这里如果信号槽在同一个线程这里同DirectConnection;如果信号和槽在不同的线程,这里同QueuedConnection |
DirectConnection |
发射完信号,槽函数立马执行,只有该槽函数执行完成后,接下来的程序才可以继续执行。 |
QueuedConnection |
这个用到多线程中,在槽函数对象的线程中其他循环结束后执行此函数。发射信号后面代码会立即执行。 |
BlockingQueuedConnection |
这个用到多线程中,在槽函数对象的线程中其他循环结束后执行此函数。发射信号后面代码不会执行指导槽函数结束。 |
UniqueConnection |
同AutoConnection |
举例说明:
还是server-socket说明:
为了挂载多个客户端,我们在数据接收线程里面这样的逻辑,每当一个客户端长链接过来我们都使用connect 连接,完成多个客户端数据的接收。如下代码:
connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){tcp_data=tcpSocket->readAll(); emit decode_data(&tcp_data);}
这里数据接收和处理是跨线程的。如果我们还像上面那样定义:
connect(data_rev,&myTcpserver::decode_data,data_rev_analyse,&data_analyse::work_start);就错了,出问题会。因为这里 Qt::ConnectionType类型是AutoConnection的导致问题很多:
(1)tcp_data 是临时变量开辟到栈内存中会被释放,你跨线程就成了野指针
(2)多个客户端同时法数据导致tcp_data被覆盖出错。
所以这里定义成connect(data_rev,&myTcpserver::decode_data,data_rev_analyse,&data_analyse::work_start,QT:BlockingQueuedConnection);
这样等解析槽函数执行完成后在执行emit decode_data(&tcp_data);后面程序没问题了。
』