引用 http://blog.csdn.net/flyoxs/article/details/54617342

简单用法

QWaitCondition 用于多线程的同步,一个线程调用QWaitCondition::wait() 阻塞等待,直到另一个线程调用QWaitCondition::wake() 唤醒才继续往下执行。

为了描述方便,这里假设主线程调用Send()往通信口发送一个数据包,然后阻塞等待回包才继续往下执行。另一个线程(通信线程)不断从通信口中接收数据并解析成数据包,然后唤醒主线程。下面是按网上给的最简单的方法:

// 示例一

// 主线程
Send(&packet);//A
mutex.lock();
condition.wait(&mutex); //B
if (m_receivedPacket)
{
HandlePacket(m_receivedPacket); // 另一线程传来回包
}
mutex.unlock(); //C
// 通信线程
m_receivedPacket = ParsePacket(buffer); // 将接收的数据解析成包
condition.wakeAll();

通常情况下,上述代码能跑得很好。但在某些特殊情况下,可能会出现混乱,大大降低通信可靠性。

在主线程中,调用 Send(&packet) 发送后,假如通信线程立即收到回包,在主线程还来不及调用 wait() 的时候,已经先 wakeAll() 了,显然这次唤醒是无效的,但主线程继续调用 wait(),然后一直阻塞在那里,因为该回的包已经回了。经测试出现这种现象的概率还是挺大的,因为我们不敢保证主线程总会被优先调度。即使主线程已经调用了 wait(),也不能保证底层操作系统的 wait_block 系统调用先于 wake 系统调用,毕竟wait() 函数也是层层封装的。

严谨用法

QWaitCondition::wait() 在使用时必须传入一个上锁的 QMutex 对象。这是很有必要的。而上述示例一代码中,我们虽然用了 mutex,但只是为了形式上传入QMutex参数,让编译器能正常编译而已,事实上,没有其它任何线程再用到这个mutex。而 mutex 本来就是让多个线程能协调工作的,所以上述示例一主线程用的 mutex 是无效的。

根据 Qt 手册,wait() 函数必须传入一个已上锁的 mutex 对象,在 wait() 执行过程中,mutex一直保持上锁状态,直到调用操作系统的wait_block 在阻塞的一瞬间把 mutex 解锁(严格说来应该是原子操作,即系统能保证在真正执行阻塞等待指令时才解锁)。另一线程唤醒后,wait() 函数将在第一时间重新给 mutex 上锁(这种操作也是原子的),直到显示调用 mutex.unlock() 解锁。

在通信线程也用上 mutex 后,整个通信时序正常了,完全解决了示例一的问题。代码如下:

// 示例二

// 主线程
mutex.lock();//A'
Send(&packet);
condition.wait(&mutex); //B‘
if (m_receivedPacket)
{
HandlePacket(m_receivedPacket); // 另一线程传来回包
}
mutex.unlock(); // 通信线程
m_receivedPacket = ParsePacket(buffer); // 将接收的数据解析成包
mutex.lock();//C‘
condition.wakeAll();
mutex.unlock();

上述示例二中,主线程先把 mutex 锁占据,即从发送数据包开始,一直到 QWaitCondition::wait() 在操作系统层次真正执行阻塞等待指令,这一段主线程的时间段内,mutex 一直被上锁,即使通信线程很快就接收到数据包,也不会直接调用 wakeAll(){见//C‘},而是在调用 mutex.lock() 时阻塞住(因为主线程已经把mutex占据上锁了,再尝试上锁就会被阻塞){见//A‘},直到主线程 QWaitCondition::wait() 真正执行操作系统的阻塞等待指令并释放mutex{见//B'},通信线程的 mutex.lock() 才即出阻塞,继续往下执行{见//C‘},调用 wakeAll(),此时一定能唤醒主线程成功。

由此可见,通过 mutex 把有严格时序要求的代码保护起来,同时把 wakeAll() 也用同一个 mutex 保护起来,这样能保证:一定先有 wait() ,再有 wakeAll(),不管什么情况,都能保证这种先后关系,而不至于摆乌龙。

QWaiteCondition思考4的更多相关文章

  1. QWaiteCondition 思考5

    1: 一个QWaiteCondition(A)  和若干个QMutex(M) 协作 同步若干个QThread. 其中QWaiteCondition(A) 中存在一个列表(listmutex)保存和其协 ...

  2. QWaiteCondition思考3

    QWaitConditioin::wait() 接收一个mutex作为参数,这个mutex应该被调用线程初始化为锁定状态.在线程进入休眠状态(waite)之前,mutex会被解锁.当线程被唤醒(Wak ...

  3. 领域驱动和MVVM应用于UWP开发的一些思考

    领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...

  4. 关于面试题 Array.indexof() 方法的实现及思考

    这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...

  5. 关于 CSS 反射倒影的研究思考

    原文地址:https://css-tricks.com/state-css-reflections 译者:nzbin 友情提示:由于演示 demo 的兼容性,推荐火狐浏览.该文章篇幅较长,内容庞杂,有 ...

  6. 关于.NET参数传递方式的思考

    年关将近,整个人已经没有了工作和写作的激情,估计这个时候很多人跟我差不多,该相亲的相亲,该聚会喝酒的聚会喝酒,总之就是没有了干活的心思(我有很多想法,但就是叫不动我的手脚,所以我只能看着别人在做我想做 ...

  7. 使用NUnit为游戏项目编写高质量单元测试的思考

    0x00 单元测试Pro & Con 最近尝试在我参与的游戏项目中引入TDD(测试驱动开发)的开发模式,因此单元测试便变得十分必要.这篇博客就来聊一聊这段时间的感悟和想法.由于游戏开发和传统软 ...

  8. OpenGL shader 中关于顶点坐标值的思考

    今天工作中需要做一个事情: 在shader内部做一些空间距离上的计算,而且需要对所有的点进行计算,符合条件的显示,不符合条件的点不显示. 思路很简单,在vertex shader内知道顶点坐标,进行计 ...

  9. 关于领域驱动设计(DDD)中聚合设计的一些思考

    关于DDD的理论知识总结,可参考这篇文章. DDD社区官网上一篇关于聚合设计的几个原则的简单讨论: 文章地址:http://dddcommunity.org/library/vernon_2011/, ...

随机推荐

  1. Nginx配置文件及模块解析

    一.Nginx是什么? Nginx是一个基于c语言开发的高性能http服务器及反向代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu.内 ...

  2. 爬虫(四)requests模块1

    引入 Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用. 警告:非专业使用其他 HTTP 库会导致危险的副作用,包括:安全缺陷症.冗余代码症.重新发明轮子症.啃文档 ...

  3. C# List<string> to string

    List<string> names = new List<string>() { "John", "Anna", "Moni ...

  4. 跟随我在oracle学习php(14)

    CSS3的@keyframes用法详解: 此属性与animation属性是密切相关的,关于animation属性可以参阅CSS3的animation属性用法详解一章节. 一.基本知识: keyfram ...

  5. Python运行时的常见错误

    1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加冒号(:)(导致 “SyntaxError :invalid syntax”) 2)使用 ...

  6. SpringMVC流程架构基础理论

    Spring web mvc和Struts2都属于表现层的框架 1. 用户发起request请求至控制器(Controller) 控制接收用户请求的数据,委托给模型进行处理 2. 控制器通过模型(Mo ...

  7. Android使用Jenkins自动化构建测试打包apk

    Jenkins这东西搭建起来真是一点也不省心啊,看着别人的教程摸着石头过河,配置的东西有点多啊,稍有不慎,就构建不成功啦!即使步骤跟别人一样也会报各种乱七八糟的错误啊哈哈~~这东西只能佛系搭建~~在经 ...

  8. Centos 安装dhcp及简单配置

    install yum -y install dhcp file /etc/dhcp/dhcpd.conf eg:-------------------------------- ddns-updat ...

  9. IoT experitment

    Abstract: In order to solve the problems of complex experiment management, complicated teaching task ...

  10. springboot 热部署

    1 pom文件添加 <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...