写目录标题
前言
嵌入式中经常使用到回调事件,比如生产者生产数据后将数据回调到消费者的缓存中,这里面涉及到2个技术,一个是回调, 另外一个是数据的并发和同步, 本主题主要讲回调。
c中的使用
这个比较简单, 因为没有涉及到数据的封装,或者说作用域都是public吧,比如struct之类的。
c++中的使用
方案1:使用static方式
该方式和c中一致, 如果代码做到高聚低耦,可以用注册的方式比较好。
方案2:使用c++11中的function以及bind
方案3:使用::方式
方案4:使用callback(datafunc pf, void *pUserData);
代码
代码有贴出了方案2和方案3的测试demo,使用非常方便
./a.out 1
其中1表示使用::的方式, 2表示function+bind方式
header
#ifndef MY_BIND_H__
#define MY_BIND_H__
#include <vector>
#include <functional>
#include <iostream>
#include <memory>
struct srcImagData
{
char *data;
unsigned int siz;
srcImagData():data(nullptr), siz(0){}
};
class CTest
{
public:
typedef std::vector<srcImagData> DataVec;
static CTest* inst()
{
static CTest ct;return &ct;
}
void dataCB( const srcImagData &lhs_data);
void show() const
{
for(const auto &x : *data_)
{
std::cout << "siz: " << x.siz << std::endl;
}
}
std::function<void(srcImagData&)> callback_data_;
private:
CTest();
~CTest();
std::shared_ptr<DataVec> data_;
};
#endif
src
#include "bind.h"
CTest::CTest():data_( new DataVec )
{
callback_data_ = std::bind(&CTest::dataCB, this, std::placeholders::_1);
}
CTest::~CTest(){
auto it = data_->begin();
for(;it != data_->end(); ++it)
{
if(it->data)
{
free(it->data); it->data = nullptr;
it->siz = 0;
}
}
std::cout << "Done." << std::endl;
}
void CTest::dataCB( const srcImagData &lhs_data)
{
#if 0
if(lhs_data.data)
{
std::cout << "data nullptr" << std::endl;
return ;
}
#endif
data_->push_back(lhs_data);
}
#if 1
enum
{
CallBack_static = 0x00, //该方式比较简单, 不做程序展示, 和c中非封装的差不多
CallBack_used_pulic ,
CallBack_function //推荐
};
int main(int argc, char *argv[])
{
if(argc < 2)
{
std::cout << "Usage: " << argv[1] << " 0" << std::endl;
return -1;
}
int sel = atoi(argv[1]);
using namespace std::placeholders; //adds visibility of _1, _2, _3,...
switch(sel)
{
case CallBack_used_pulic:
{
void (CTest::*pTestFunc4)(const srcImagData& );
pTestFunc4 = &CTest::dataCB;
for(int i = 0; i< 10; i++)
{
srcImagData t;
//do somethings ... TODO: e.g malloc image data
//释放在析构中释放
t.siz = 100 * i;
(CTest::inst()->*pTestFunc4)(t);
}
CTest::inst()->show();
}break;
case CallBack_function:
{
srcImagData t;
for(int i = 0; i < 10; i++)
{
//
t.siz = 100*i;
CTest::inst()->callback_data_(t);
}
CTest::inst()->show();
}break;
}
return 0;
}
#endif
代码II:
/**
注册: 注册时带方法地址 + 类方法的实例指针
调用: 将数据到push到注册的实例中,同时将实例的地址图传给实调用者
该方式兼容了c的接口, 针对模块设计为第三方的,使用c的方式的回调接口,如果
使用的是c++的接口, 可以通过std::functional中的std::bind()更好
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include <string>
#include <iostream>
#include <string.h>
#define BUF_MAX (1024)
typedef struct MyStruct
{
char buf[BUF_MAX];
}MyStruct_S;
typedef void (*datafunc)(const MyStruct_S *pData, void *pUserData);
/*注册端*/
class CMyClass
{
public:
CMyClass();
~CMyClass();
/*注意第二个形参的意思, 主要是静态方法中无法使用类的数据和方法*/
static void requestCB(const MyStruct_S*, void*);
int setMyStructData(const MyStruct_S *pMyData);
private:
//datafunc dataCallback_;
MyStruct_S myStructData_;
};
CMyClass::CMyClass(){}
CMyClass::~CMyClass(){}
int CMyClass::setMyStructData(const MyStruct_S *pMyData)
{
if(pMyData)
{
printf("%s.\n", pMyData->buf);return -1;
memcpy(&myStructData_, pMyData, sizeof(MyStruct_S));
}
}
void CMyClass::requestCB(const MyStruct_S *pdata, void *pUserData)
{
if(!pdata || !pUserData)
{
printf("nullptr\n");return ;
}
CMyClass *pinst = (CMyClass*)pUserData;
pinst->setMyStructData(pdata);
}
/*
反注册模块, 一般是数据的生产者或响应者,注意setCallback方法的第二个参数的意义
*/
class CMoudleClass
{
public:
CMoudleClass();
~CMoudleClass();
void dataCreaterProc();
void setCallback(const datafunc pf, void *); /*注册*/
private:
bool isRun_;
std::thread *pdataThread_; //数据生产者
MyStruct_S myStructData_;
datafunc datacb_;
void *pUserdata_; /*注册端的数据*/
};
CMoudleClass::CMoudleClass():pdataThread_(nullptr), isRun_(true), datacb_(nullptr), pUserdata_(nullptr)
{
pdataThread_ = new std::thread(&CMoudleClass::dataCreaterProc, this);
if(nullptr == pdataThread_)
{
printf("create thread failure .\n");
}
}
CMoudleClass::~CMoudleClass()
{
isRun_ = false;
if(pdataThread_ )
{
if( pdataThread_->joinable()) pdataThread_ ->join();
delete pdataThread_; pdataThread_ = nullptr;
}
}
/*
@brief 地址填充
@params[in] pf - 调用者的地址 pUserData - 调用者的实例地址
@return null
*/
void CMoudleClass::setCallback(const datafunc pf, const void *pUserData)
{
datacb_ = pf;
pUserdata_ = pUserData;
}
void CMoudleClass::dataCreaterProc()
{
while(isRun_)
{
static int cnt = 0;
if(datacb_)
{
memset(&myStructData_, 0, sizeof(MyStruct_S));
snprintf(myStructData_.buf, BUF_MAX-1, "%08d", ++cnt);
datacb_(&myStructData_, pUserdata_);
sleep(1);
}else{sleep(2);}
}
}
int main(int argc, char *argv[])
{
CMyClass myclassInst;
CMoudleClass cModuleInst;
cModuleInst.setCallback(myclassInst.requestCB, (void*)&myclassInst);
while(1)
{
sleep(3);
}
}