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