当前位置:网站首页>QWaitCondition 的正确使用方法
QWaitCondition 的正确使用方法
2022-07-24 12:24:00 【天天进步2015】
简单用法
QWaitCondition 用于多线程的同步,一个线程调用QWaitCondition::wait() 阻塞等待,直到另一个线程调用QWaitCondition::wake() 唤醒才继续往下执行。
为了描述方便,这里假设主线程调用Send()往通信口发送一个数据包,然后阻塞等待回包才继续往下执行。另一个线程(通信线程)不断从通信口中接收数据并解析成数据包,然后唤醒主线程。下面是按网上给的最简单的方法:
// 示例一
// 主线程
Send(&packet);
mutex.lock();
condition.wait(&mutex);
if (m_receivedPacket)
{
HandlePacket(m_receivedPacket); // 另一线程传来回包
}
mutex.unlock();
// 通信线程
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();
Send(&packet);
condition.wait(&mutex);
if (m_receivedPacket)
{
HandlePacket(m_receivedPacket); // 另一线程传来回包
}
mutex.unlock();
// 通信线程
m_receivedPacket = ParsePacket(buffer); // 将接收的数据解析成包
mutex.lock();
condition.wakeAll();
mutex.unlock();
上述示例二中,主线程先把 mutex 锁占据,即从发送数据包开始,一直到 QWaitCondition::wait() 在操作系统层次真正执行阻塞等待指令,这一段主线程的时间段内,mutex 一直被上锁,即使通信线程很快就接收到数据包,也不会直接调用 wakeAll(),而是在调用 mutex.lock() 时阻塞住(因为主线程已经把mutex占据上锁了,再尝试上锁就会被阻塞),直到主线程 QWaitCondition::wait() 真正执行操作系统的阻塞等待指令并释放mutex,通信线程的 mutex.lock() 才即出阻塞,继续往下执行,调用 wakeAll(),此时一定能唤醒主线程成功。
由此可见,通过 mutex 把有严格时序要求的代码保护起来,同时把 wakeAll() 也用同一个 mutex 保护起来,这样能保证:一定先有 wait() ,再有 wakeAll(),不管什么情况,都能保证这种先后关系,而不至于摆乌龙。
推而广之
mutex 和 condition 联合使用是多线程中的一个常用的设计模式,不仅是 Qt,对于 C++ 的 std::condition_variable 和 std::mutex ,以及 java 的 synchronized / wait / notify 也都适用。
————————————————
版权声明:本文为CSDN博主「flyoxs」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/flyoxs/article/details/54617342
边栏推荐
- Understand what goals the MES system can achieve
- Examples of map search
- Ansible的安装及部署
- 如何将Typora中图片上传到csdn
- Qt5.12 + vs2019 cannot locate the program input point in the dynamic link library
- SQL multi condition query cannot be implemented
- [Commons beanautils topic] 005- convertutils topic
- Buckle practice - 27 score after turning the matrix
- 【功能测试】项目的测试——登录和发布文章功能
- Leecode-268. missing numbers (Application of XOR, find numbers that do not appear, find numbers that only appear once)
猜你喜欢

Miss waiting for a year! Baidu super chain digital publishing service is limited to 50% discount

Aruba learning notes 04 Web UI -- Introduction to configuration panel

Conference publishing function of conference OA project
![[mathematical basis of Cyberspace Security Chapter 3] congruence](/img/00/42a5f7f6f0e8a50884f4639767949f.jpg)
[mathematical basis of Cyberspace Security Chapter 3] congruence

Installation and deployment of ansible

QT notes - qtxml
![ERROR: [Synth 8-439] module ‘xxx‘ not found not found 错误解决办法](/img/47/bb03cc26e254332bf815c80bafb243.png)
ERROR: [Synth 8-439] module ‘xxx‘ not found not found 错误解决办法

微信小程序生成二维码

动态内存管理
![[function test] test of the project - login and post function](/img/64/c9bbf34964622f4f013b1184eeb1e0.jpg)
[function test] test of the project - login and post function
随机推荐
QT notes - sort a column specified by qtablewidget
02 linear structure 2 multiplication and addition of univariate polynomials (linked list solution)
[mathematical basis of Cyberspace Security Chapter 9] finite field
一文看懂MES系统能实现企业哪些目标
L2-011 play with binary tree
What is prescaler in STM32
有没有2、3w前期适合一个人干的创业项目呢?做自媒体可以吗?
Buckle practice - 24 remove repeated letters
Markdown mathematical formula syntax
In kuborad graphical interface, operate kubernetes cluster to realize master-slave replication in MySQL
Browser logic vulnerability collection
Delphi gexperts expert instructions for improving development efficiency
4*4图片权重的收敛规则
QT notes - realize form adaptation
Calculate the distance between the longitude and latitude of two coordinates (5 ways)
Aruba learning notes 04 Web UI -- Introduction to configuration panel
PM's alarm: "NPM warn config global --global, --local are deprecated
L1-049 seat allocation of ladder race
Wechat applet - drawing dashboard
for mysql