QT中的signal/slot的事件

最近在使用QT的时候遇到不少困难,幸好主要参考这两个网站,现在都基本解决了:
http://www.qtcn.org/
http://www.qtforum.org/

在此也总结一下:

QT中的signal/slot的事件机制都是基于主程序的线程的,(辅线程中不可能使用signal,原因稍后说明),因此所有的事件都是阻塞型的,也就是说除非你处理完某个slot事件,不然不会有下个事件被触发。

但是,在此有一个例外,那就是QTimer,timerEvent(QTimerEvent *e)事件是会重复进入的,只要时间到了,无论你之前一次的timerEvent(QTimerEvent *e)事件是否结束,程序都会再次进入,很抱歉QTimer的代码我没有看懂,因此不知道它是怎么实现的。

其次,关于QT中用于网络通讯的类QSocket,想要使用QSocket接收数据的话,就必须connect其readyRead()事件,但是正如前面所说的,所有signal/slot的触发都是基于主线程的,所以你实现的slotReadyRead()代码将在主线程中被触发,如果你的程序需要接收大量的数据,或者对数据进行一定的验证工作,(正如我现在所做的),那么把这个比较耗时的工作放在主线程中是不可行的。

那么比较容易想到的办法是将QSocket放到线程中,但是其实这样是不可行的,(1),QThread不是QObject继承而来的,不能使用任何signal/slot机制,看到网上有人用多重继承的方法同时从QThread和QObject继承出新的类来用,但是实践证明这样也是不可行的。(2),那么在QThread中再加入一层从QObject继承得的类,负责connect到QSocket的readyRead()事件呢,由于之前讲过,QT的signal/slot完全是靠主线程实现的,所以很不幸,最后你的slotReadyRead()方法最终的执行者仍然是主线程,QThread成为了摆设。。

我翻阅了QT的文档,和论坛中N人的提问,得到的结论是,如果要实现异步的数据采集功能,那么应该结合QThread和QSocketDevice两个类,QSocketDevice不像QSocket那样,任何数据到达它都不会触发事件,相反的,你必须主动调用它的函数,查询是否有数据到达,或者干脆调用wait函数,阻塞程序,直到有数据到达为止,对于主线程来说阻塞是不可行的,但是对于线程来说,要的就是这种效果。

那么一旦数据正常接收完毕了呢,此时数据采集线程必须主动通知主线程中的数据处理类,翻阅QT文档,找到了QThread要向主线程发送信息,必须使用QApplication::postEvent()函数,只有这个函数才是线程安全的,于是我使用了它,但是结果却发现了另一个严重的问题,那就是QApplication::postEvent()函数是阻塞型的,调用它的线程将等待主线程中的处理函数返回,才会继续,而我的程序中数据采集的速度有可能大于主线程的处理速度,此时我会在线程中提供缓存功能,而不能让采集停止了,那么也就是说,我需要的通知方法必须是异步的才行。

在这里,首先想到的办法是使用QTimer,因为它是非阻塞型的,但是很抱歉,在这种时间要求比较敏感的场合,我不希望使用QTimer。

怎么办呢,我在论坛上没有找到什么有用的资料(可能是我英文比较烂),最后只能自己实现了,那就是再使用一个线程(就把它叫做事件通知线程),内部使用QWaitCondition,让该线程始终处于等待状态,一旦数据采集线程收到数据,它就唤醒事件通知线程中的QWaitCondition,此时事件通知线程会使用QApplication::postEvent()来向主线程发送事件。N时间以后,假设此时主线程正在处理数据,事件发送线程的postEvent()过程尚未返回,而数据采集线程中又有数据到达,它并不会知道事件发送线程中的状态,而是简单的再次唤醒QWaitCondition,但是作为事件发送线程,对QWaitCondition的多次唤醒将不会有任何影响,它继续阻塞在postEvent中。又N时间后,事件发送线程中的postEvent()返回了,此时它设置自己的QWaitCondition再次进入等待状态,它将一直等待,直到下载数据采集线程再次唤醒它。
总结一下,其实就是在事件发送线程中,如果当时正在处理postEvent(),那么它将自动忽略数据采集线程发来的任何更新命令。

而我的主线程中的处理程序在被通知时,会自动查找数据缓存中的所有数据进行处理。这样将清空所有缓存中积压的数据。

就那么简单,不过我整整花了三天才逐步实现了以上的功能,希望能对大家有用。

最后,来一张最近这个程序在Linux下运行的快照:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值