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 
Receiver::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(); } }}
(2)适配层,把发送和接收封装成一个服务,提供给上层应用使用
udsadaptation.h
#ifndef UDSADAPTATION_H#define UDSADAPTATION_H#include 
#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
udsadaptation.cpp
#include "udsadaptation.h"#include 
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);}
(3)上层应用调用
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技术是个不错的选择。
上一篇:Linux Block块设备层请求request
下一篇:Linux AHCI驱动分析之块设备层

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年04月08日 16时14分53秒