c++回调

前言

嵌入式中经常使用到回调事件,比如生产者生产数据后将数据回调到消费者的缓存中,这里面涉及到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);
	}
	
	
}

猜你喜欢

转载自blog.csdn.net/nc_linux/article/details/129484043