Reputation: 5586
I have a library which sources I may not change. It has a structure that contains function pointer which is a callback for some event. Consider:
// library code (.h file)
typedef int (callback_function)(int arg1, double arg2);
struct callbacks_struct
{
...
callback_function *callback;
...
};
I'm writing a C++ wrapper for this low-level stuff. Consider I have a class:
class Wrapper
{
public:
int Callback(int arg1, double arg2);
};
Now I want to bind Wrapper::Callback
to be used as a callback when creating structure callback_struct
:
struct callback_struct x[] =
{
{
...
// put a Wrapper::Callback as a callback
...
},
{0, 0, 0, 0}
}
Obviously, this can not be done without some intermediate function. The one way is to make a global object of Wrapper
class and use it:
std::shared_ptr<Wrapper> gWrapper;
void foo()
{
struct callback_struct x[] =
{
{
...
my_plain_callback,
...
},
{0, 0, 0, 0}
}
}
int my_plain_callback(int arg1, double arg2)
{
return gWrapper->Callback(arg1, arg2);
}
But I need a thread-safe solution, so using global variable seems to be a source of problems in this case.
Does anyone know better solution?
Thanks.
Upvotes: 1
Views: 529
Reputation: 7744
It may help you:
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <stdexcept>
#include <mutex>
class Wrapper
{
typedef std::mutex mutex_type;
typedef std::unique_lock<mutex_type> locker;
public:
typedef boost::function<int(int,double)> call_backtype;
static int callBackFunction(int arg1_, double arg2_)
{
locker l(_mutex);
if ( my_call.empty() ) {
throw std::runtime_error("No callback function was set!");
}
return my_call(arg1_,arg2_);
}
static void setCallBack( const call_backtype& func_ )
{
locker l(_mutex);
_my_call = func_;
}
private:
static mutex_type _mutex;
static call_backtype _my_call;
Wrapper(void){}
};
class any_other_class
{
int do_anything(int arg1_, double arg2_);
void setThisAsCallback()
{
Wrapper::setCallBack(boost::bind(&any_other_class::do_anything,this,_1,_2));
}
};
// to C interface (use the static method):
setCallBack(&Wrapper::callBackFunction);
Upvotes: 1
Reputation: 71989
Use a thread-local variable for the callback state.
Or go the hardcore route and use some platform-dependent code to generate a stub that injects the pointer.
Upvotes: 2