
QWaitCondition把异步调用封装成同步调用
发布日期:2021-05-08 04:05:44
浏览次数:10
分类:精选文章
本文共 4695 字,大约阅读时间需要 15 分钟。
QWaitCondition
前言
我们在开发应用程序的时候,经常需要使用多线程技术实现业务流程,如果我们在子线程处理业务的过程中,依赖另一个线程执行的结果来决定是否继续执行后续的任务时,这时候就需要使用到多线程的同步技术。多线程同步技术有很多,这篇博文介绍的多线程同步技术是Qt 的QWaitCondition,因为最近工作中有使用到这项技术,觉得非常有用,所以分享出来,共同提高我们的编程技术。一、QWaitCondition简介
QWaitCondition 类提供一个条件变量用于线程同步,当一些有序的条件被满足时,会通知其他等待这个条件的线程。一个或多个线程可以根据业务需要,阻断线程的执行,等待一个QWaitCondition对象通过wakeOne()或者wakeAll()设置一个条件变量。使用wakeOne()唤醒随机的等待线程;使用wakeAll()唤醒所有的等待线程。二、QWaitCondition的应用
1.应用背景
我们在开发程序的时候,绝大多数的接口的调用方式是同步方式,即调用后函数返回值即是函数执行的结果。可是有的时候,函数的调用和业务的执行结果并不在同一个线程中,函数的调用并不能直接获得结果,例如can总线的UDS诊断传输层中,发送诊断请求是一个线程,接收诊断结果在另一个线程,这种调用方式称为异步调用方式。可是异步调用方式使用起来非常不方便,增加了业务控制的难度。所以,我们希望把异步调用方式做封装,把异步调用封装成同步调用方式。2.实现目标及设计思路
设计目标:通过QWaitCondition把异步调用封装成同步调用。 设计思路:通过增加适配层,把异步返回的接收数据和请求数据封装成一个业务函数。适配层先调用发送函数推送数据到服务器,然后通过QWaitCondition对象等待接收结果,收到结果后,函数返回。这样,上层应用可以不再使用异步方式实现业务,直接使用同步调用方式即可完成业务,获得需要的接收数据,极大的简化了上层应用的代码逻辑。 举例说明:举的例子是CAN总线UDS服务的会话控制服务,按照协议描述,传输层的实现应该是异步方式实现的通信逻辑,上层应用需要提供回调函数给通信层,当通信层收到数据时,调用回调函数,通知上层应用,提示收到了服务器数据。我们这里举的例子,是多封装了一层,把服务的收发封装到适配层当中,上层应用只需调用服务接口,即可实现同步方式发生服务请求,函数返回时获取接收到的数据,这样,上层应用的代码将得到极大的简化。3.代码实现
(1)接收线程,负责接收服务器的相应数据。 receiver.h#ifndef RECEIVER_H#define RECEIVER_H#include#include #include class Receiver : public QThread{ public: Receiver(QWaitCondition* condition, QMutex* mutex); int get_receive_data(unsigned char* buff, int buff_len); void to_stop();protected: void run();private: int read_data_from_server(unsigned char* buff, int buff_len);private: bool m_stop = false; QWaitCondition* m_waite_result = NULL; QMutex* m_mutex = NULL; unsigned char m_buff[10] = { 0}; int m_valid_data_len = 0;};#endif // RECEIVER_H
receiver.cpp
#include "receiver.h"#include(2)适配层,把发送和接收封装成一个服务,提供给上层应用使用 udsadaptation.hReceiver::Receiver(QWaitCondition *condition, QMutex *mutex){ m_waite_result = condition; m_mutex = mutex;}void Receiver::to_stop() { m_stop = true;}//模拟从服务器读数据int Receiver::read_data_from_server(unsigned char* buff, int buff_len) { if (buff == NULL || buff_len < 5) { return 0; } //50 02 00 32 01 F4 int index = 0; buff[index++] = 0x50; buff[index++] = 0x02; buff[index++] = 0x00; buff[index++] = 0x32; buff[index++] = 0x01; buff[index++] = 0xF4; return 6;}int Receiver::get_receive_data(unsigned char* buff, int buff_len){ if (m_valid_data_len > 0 && buff_len >= m_valid_data_len) { memcpy(buff, m_buff, m_valid_data_len); printf("get data from server:"); int index = 0; while (index < m_valid_data_len) { printf("%02x ", m_buff[index]); index++; } return m_valid_data_len; } return 0;}void Receiver::run(){ while (!m_stop) { m_mutex->lock(); int len = read_data_from_server(m_buff, sizeof(m_buff)); m_mutex->unlock(); if (len >= 5) { m_valid_data_len = len; m_waite_result->wakeAll(); } }}
#ifndef UDSADAPTATION_H#define UDSADAPTATION_H#includeudsadaptation.cpp#include "receiver.h"#include class UdsAdaptation{ public: UdsAdaptation(); ~UdsAdaptation(); int DiagnosticSessionControl(const unsigned char* req, const int req_len, unsigned char*buff, int buff_len);private: int send_data_to_server(const unsigned char* req, int req_len);public: QWaitCondition waite_result; QMutex m_mutex; Receiver* m_reveiver = NULL;};#endif // UDSADAPTATION_H
#include "udsadaptation.h"#include(3)上层应用调用UdsAdaptation::UdsAdaptation(){ m_mutex.lock(); m_reveiver = new Receiver(&waite_result, &m_mutex); m_reveiver->start();}UdsAdaptation::~UdsAdaptation() { m_mutex.unlock(); m_reveiver->to_stop(); m_reveiver->wait(); delete m_reveiver;}// 模拟推送到服务器int UdsAdaptation::send_data_to_server(const unsigned char* req, int req_len) { printf("push data to server:"); int index = 0; while (index < req_len) { printf("%02x ", req[index]); index++; } printf("\n"); return req_len;}int UdsAdaptation::DiagnosticSessionControl(const unsigned char* req, const int req_len, unsigned char*buff, int buff_len) { int send_len = send_data_to_server(req, req_len); waite_result.wait(&m_mutex); return m_reveiver->get_receive_data(buff, buff_len);}
unsigned char req[2]; req[0] = 0x10; req[1] = 0x02; unsigned char buff[10] = { 0}; UdsAdaptation uds_adaptation; int received_len = uds_adaptation.DiagnosticSessionControl(req, sizeof(req), buff, sizeof(buff));
总结
QWaitCondition配合mutex,很好的实现了多线程中的序列化处理。既利用了多线程的效率,又实现的既定的执行顺序,达到程序高效运行的目的。当我们的程序需要停下来,等待另一个线程执行的结果时,使用QWaitCondition技术是个不错的选择。发表评论
最新留言
网站不错 人气很旺了 加油
[***.192.178.218]2025年04月08日 16时14分53秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
求二维数组中最大值的位置
2021-05-08
python中sort和sorted的区别
2021-05-08
防碰撞算法
2021-05-08
在vue中添加echarts
2021-05-08
vue中echart数据动态切换,一看就懂
2021-05-08
Python实现理解树,树的遍历,二分查找
2021-05-08
Python3.6爬虫记录
2021-05-08
搞清楚Spring Cloud架构原理的这4个点,轻松应对面试
2021-05-08
1月份2月份GitHub上最热门的23个Java开源项目
2021-05-08
maven安装
2021-05-08
2020第十五届全国大学生智能汽车竞赛——4X4矩阵键盘+Flash调参系统
2021-05-08
合并两个有序数组
2021-05-08
Ubuntu 环境下使用中文输入法
2021-05-08
小白学习Vue(?)--model选项的使用(自定义组件文本框双向绑定)
2021-05-08
聊聊我的五一小假期
2021-05-08
面向对象之异常处理:多路捕获
2021-05-08
Python简易五子棋
2021-05-08
MySQL8.0.19 JDBC下载与使用
2021-05-08
Windows安装MongoDB 4.2.8
2021-05-08
Vue新建项目——页面初始化
2021-05-08