电子网站模板/优秀的营销案例
QWaitCondition
- 前言
- 一、QWaitCondition简介
- 二、QWaitCondition的应用
- 1.应用背景
- 2.实现目标及设计思路
- 3.代码实现
- 总结
前言
我们在开发应用程序的时候,经常需要使用多线程技术实现业务流程,如果我们在子线程处理业务的过程中,依赖另一个线程执行的结果来决定是否继续执行后续的任务时,这时候就需要使用到多线程的同步技术。多线程同步技术有很多,这篇博文介绍的多线程同步技术是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 <QThread>
#include <QWaitCondition>
#include <mutex>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 <QMutex>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 F4int 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 <QWaitCondition>
#include "receiver.h"
#include <qmutex.h>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 <stdio.h>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));