pybind11: C/C++端回调函数

引言

需要用pybind11对C/C++函数库进行封装,其中需要在Python端提供回调函数功能:即回调函数和传给该函数的变量都在Python端定义。因底层驱动的回调函数是C语言实现,接收一个void*指针变量,pybind11中实现起来比较困难。


C/C++端的回调函数定义

#include 
#include 

namespace py=pybind11;

//回调函数类型
typedef void(*CallbackFunc)(void*);

//使用例子
struct UserData{ int a=0; int b=0;}
void callback(void *userData)
{
	UserData *data=reinterpret_cast<UserData*>(userData);
	data->a++;
	data->b++;
	return;
}

//调用回调函数
void do_callback(void *userData, CallbackFunc cb)
{
	(*cb)(userData);
}

pybind11 C/C++部分代码



using PyCallbackFunc=std::function<void(py::object)>;
struct Context{
	py::object userData;
	PyCallbackFunc callback;
};

void pycallback(void *context)
{
	auto ctx=static_cast<Context*>(contex);
	
	//2022.01.01,调用python函数,需要获得gil
	//pycallback可能在多线程环境下使用
	py::gil_scoped_acquire gil;
	ctx->callback(ctx->userData);
}	

//通过Context类型包装,适配CallbackFunc回调接口
void test_pycallback(py::object userData, PyCallbackFunc cb)
{
	Context context{userData, cb};
	//调用Python端回调函数
	do_callback(&context, pycallback);
}

PYBIND11_MODULE(MyCallback,m){
    m.doc()="pybind11 callback demo";
    m.def("test_pycallback",&test_pycallback);
}

pybind11 Python部分代码

import MyCallback

class UserData:
	def __init__(self):
		self.a=0
		self.b=0
	def print(self):
		print("a=",self.a,"b=",self.b)

def callback(userData):
	userData.a+=1
	userData.b+=1

userData=UserData()
userData.print()

MyCallback.test_pycallback(userData,callback)
userData.print()
MyCallback.test_pycallback(userData,callback)
userData.print()


你可能感兴趣的:(c++,python)