how to gracefully handle C callbacks from C++ code? - c++

I'm using a C library where the user is supposed to register a int (*functionPtr)(int,int); callback.
Then, some file is processed, and during the file processing the user receives callback with the previously given function, up to thousands for a single file processing.
My question is, how to manage state for this kind of worflow?
For instance I'd like to count how many times the callback was called. The only way I'm thinking of doing this is :
int c = 0; //global variable
int callback(int i, int j) {
++c;
}
Which is basically not very pretty and forces me to manage global variables.
Is there a way to do this effeciently in C++ ? In my case I do not have access to C++11

The standard way is to support a context pointer:
void myAPI(void (*f)(void *, int, int), void *context) {
...
// Call the callback passing the provided context
f(context, x, y);
...
}
The users can then recover custom data from the context if needed... for example
void inc_counter(void *context, int x, int y) {
*((int *)context) += 1;
}
void foo() {
int count = 0;
myAPI(inc_counter, &count);
}
In other words the idea is to add an opaque void * parameter to the callback interface and also a void * value to pass in that parameter when invoking the function.
This doesn't add any coupling but works around the problem that C has no closures.

Related

OpenCV passing values by reference or pointer to callback functions

I'm trying to avoid using global variables in an openCV project (I'll have my supervisor no doubt teach me as to why they are bad rah rah rah :) - but at the moment they seem to be the only way I can get information out of mouse and trackbar callback functions.
Using the mouse example - at the moment I have as globals:
vector<Point2d> vectorOfPoints;
int clickCount = 0;
At the moment I have this line in main:
setMouseCallback("test",onMouse, NULL);
Then above main:
void onMouse(int event, int x, int y, int f, void* ){
if(event == CV_EVENT_LBUTTONDOWN){
vectorOfPoints.push_back(Point(x,y));
clickCount++;
}
}
It is working, but what is the syntax to get read/write access to both vectorOfPoints and clickCount inside the callback function without using globals?
I have found this question online a few times but the answers are unclear to me or wont work. There are hints within comments as how to do it, but I am so far unable to interpret the jargon correctly.
I was hoping for something as simple as the syntax I use to pass variables as references to methods ...
void referenceExampleMethod(vector<Point2d>& referenceExample){
//do something with referenceExample...
}
...less convoluted the better
I'm scared to ask (jargon overload!) but maybe it's 100% relevant - what is void* ??
Any help appreciated
I agree with the first part of the #jschultz410's answer about the pointer to some place in memory. However, I disagree with using raw pointers in the wild.
You should define your own data type, holding all your data, it could be struct or class, or std::pair, or std::tuple, whatever, the choice is yours.
Then you create an object of that type and use its address in the last argument for setMouseCallback.
The main thing you must ensure - the life time of that object must cover the life time of the window. That is, the object must be created before the first call to onMouse and destroyed after the last one. You could do this by declaring the variable in the beginning of your main. Then the object will be created early after the program start and destroyed near its finish automatically by the compiler. Here is the example.
typedef std::pair<vector<Point2d>, int> data_holder_type; // note the absence of references, this pair holds std::vector and int
void onMouse(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type *dholder = static_cast<data_holder_type *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
....
int main(void) {
data_holder_type dholder;
// add code to initialize your dholder;
...
setMouseCallback("test", onMouse, &dholder);
...
cv::waitKey(); // wait until the window is closed
// read values from dholder and process them
} //dhloder is deleted somewhere here
Another important thing is the concurrent access to this object. onMouse is called from the separate parallel thread, and if your dholder is read or modified both in main, and onMouse simultaneously while the window is open, race conditions will occur. In general, they usually cause unpredictable and very hard to catch bugs.
Everything is fine while your main doesn't access dholder until the window is closed.
As for your question about void *. Note the lines inside if in onMouse. ptr points to the object of type void. That object has no any members, first, or second, or any others. You'll get the compiler error if you'll try to access them using ptr (e.g. ptr->first). Therefore you have to cast this pointer to pointer to another type, that contains some info about the object it points to, data_holder_type * in this case.
Any pointer type can be cast to void *, and void * can be cast to any other pointer type. This allows you to have several different callbacks for different windows.
Beware of wrong casts! No checks is done by compiler.
This example shows how to set 3 different mouse callbacks for windows with different titles.
typedef blah-blah-blah1 data_holder_type1;
typedef blah-blah-blah2 data_holder_type2;
typedef blah-blah-blah3 data_holder_type3;
void onMouse1(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type1 *dholder = static_cast<data_holder_type1 *>(ptr);
dholder->first.push_back(Point(x,y));
dholder->second.clickCount++;
}
}
void onMouse2(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type2 *dholder = static_cast<data_holder_type2 *>(ptr);
// processing, related to another data type
}
}
void onMouse3(int event, int x, int y, int f, void* ptr){
if(event == CV_EVENT_LBUTTONDOWN){
data_holder_type3 *dholder = static_cast<data_holder_type3 *>(ptr);
// process
}
}
int main(void) {
data_holder_type1 dholder1;
data_holder_type2 dholder2;
data_holder_type3 dholder3;
// add code to initialize your dholders;
...
setMouseCallback("test1", onMouse1, &dholder1);
setMouseCallback("test2", onMouse2, &dholder2);
setMouseCallback("test3", onMouse3, &dholder3);
...
}
The last parameter to setMouseCallback is passed back to you when onMouse is called. That is what the void * is in onMouse: the pointer that you passed to setMouseCallback. A void * is a pointer to an unspecified type. You can think of it as a generic pointer to some place in memory.
In your case, you would likely pass the address of a struct that either contains or points to the variables that you want to have access to inside onMouse.
#include <utility>
...
typedef std::pair<std::vector<Point2d>&, int&> my_pair;
...
my_pair *p = new my_pair(vectorOfPoints, clickCount); // TODO: needs to be deallocated eventually
setMouseCallback("test", onMouse, p);
The above assumes that vectorOfPoints and clickCount are already allocated somewhere else (e.g. - dynamically, statically, on the main thread's stack, etc.) and will remain so for the duration of your callbacks. Then,
void onMouse(int event, int x, int y, int f, void *pptr)
{
my_pair *p = (my_pair*) pptr;
if(event == CV_EVENT_LBUTTONDOWN){
p->first.push_back(Point(x,y));
p->second++;
}
}

Need help templatizing structure accessed by multiple threads

The problem requires implementing a ring buffer into which a producer writes and from which a consumer reads. I have done this for a data type. I want to extend this so that it will work for any primitive data type but have not been able to figure out a good way to do this. I want the program to take inputs from the command line like so "program_name data_type size_of_buffer".
I could templatize the buffer.start pointer and pass the data type around but I don't know of a way to assign the data type name to a variable. Anyone have any ideas?
struct buffer{
int * start;
int size;
}buffer;
int * producer=NULL;
int * consumer=NULL;
bool donewriting;
bool sleeping;
void *mywrite(void *);
void *myread(void *);
void *mywrite(void * ){
do{
cout<<"In Thread 1"<<endl;
static int x=0;
*producer=x;
cout<<"Write thread: wrote value "<<x<<" into buffer"<<endl;
producer++;
if(producer==buffer.start+10)
{ producer=buffer.start;
donewriting=true;
}
if(x==5)
{
cout<<"Thread 1 going to sleep"<<endl;
Sleep(2000);
}
x++;
} while(producer!=buffer.start);
}
void *myread(void *){
while(!donewriting)
{ //cout<<"In Thread 2"<<endl;
if(consumer<producer)
{ cout<<"Read thread: read value "<<*consumer<<" from buffer"<<endl;
consumer++;
}
}
}
int main()
{
buffer.size=10;
buffer.start=new int(10);
producer=buffer.start;
consumer=buffer.start;
donewriting=false;
cout<<"In main"<<endl;
pthread_t writeThread,readThread;
pthread_create(&writeThread,NULL,mywrite,NULL);
pthread_create(&readThread,NULL,myread,NULL);
pthread_join(writeThread,NULL);
pthread_join(readThread,NULL);
return 0;
}
Unfortunately, your goal is not possible given the scenario you have described. Internally, C++ programs compile templated code for each datatype used with the template. In other words, if you have a templated function x() and you call
x<int>();
x<float>();
the compiler will produce two copies of the templated function: one that uses the int datatype and another that uses the float datatype. Before you call the function, no code is produced at all. Therefore, you cannot build the program and pass arbitrary data types to it.
Of course, if the command-line call is only intended as a test for the code, and you'll use it in a library in future, you're ok - but you'll still have to specify the type you're using in your code.
The current way you're doing this, using void * is probably the best way.
It might be better to specify the size in bytes of the type you wish to use, rather than the specific type itself. As long as your final producer and consumer share knowledge of the type in question, you'll be fine.

How to pass a class method as a GLUT callback?

I know this thing works:
void myDisplay()
{
...
}
int main()
{
...
glutDisplayFunc(myDisplay)
...
}
so I tried to include myDisplay() function to a class that I made. Because I want to overload it in the future with a different class. However, the compiler complains that
argument of type 'void (ClassBlah::)()' does not match 'void(*)()' .
Here is the what I try to make:
class ClassBlah
{
....
void myDisplay()
....
}
......
int main()
{
...
ClassBlah blah
glutDisplayFunc(blah.myDisplay)
...
}
Does anybody knows how to fix this problem?
Firstly, there is an implicit "this" pointer in non-static member functions, so you'll need to change your void myDisplay() in ClassBlah to be static. It's awkward to work around this limitation, which is why the C++ faq lite says don't do it
Then, you should be able to pass the functions as ClassBlah::myDisplay.
Depending on your motivation for overloading (ie are you going to hotswap implementations in and out at runtime, or only at compile time?) you might consider a utility "handler" static class that contains a pointer to your base class, and delegates responsibility through that.
I ran into this problem writing a C++ Glut engine myself. Here's how I worked around it:
I placed these at the top of my program.cpp / main.cpp
// Function prototypes
void doRendering( void );
void processMouse( int, int ) ;
void processMouseClick(int button, int state, int x, int y);
void keyboardInput(unsigned char c, int x, int y);
Assign these functions to glut's callbacks here:
glutDisplayFunc(doRendering);
glutIdleFunc(doRendering);
glutPassiveMotionFunc(processMouse);
glutMotionFunc(processMouse);
glutMouseFunc(processMouseClick);
glutKeyboardFunc(keyboardInput);
Create my own class which handles these on its own and then make the contents of our static functions simply call methods on the instance of this class. Your main function should create a new instance of the class in main (in my case... App *newApp).
void doRendering( void )
{
newApp->updateScene();
newApp->drawScene();
}
void processMouse(int x, int y)
{
newApp->processMouse(x, y);
}
void processMouseClick(int button, int state, int x, int y)
{
newApp->processMouseClick(button, state, x, y);
}
void keyboardInput(unsigned char c, int x, int y)
{
newApp->keyboardInput(c, x, y);
}
Hope that explains it.
My way to solve this is simple:
First make a pointer before main function.
At the beginning of the the main function set pointer to instance of your class.
Then in new defined function for rendering, You can acces your object with global pointer.
/**
Class argon is defined in external header file.
*/
Argon *argonPtr;
void renderScene();
int main()
{
Argon argon;
argonPtr = &argon;
glutDisplayFunc( render );
}
void render()
{
RenderStuff();
argonPtr->Render();
}
Hope it works for You, for me it does.
You can use Boost bind for member functions, for example creating a thread on a member function:
class classA
{
public:
void memberThreadFunc(int i);
};
void main()
{
classA a;
boost::thread( boost::bind(&classA::memberFunc, &a, 123) );
}
You can't. glutDisplayFunc takes a parameter of type void(*)(), not void (ClassBlah::)(). Unless you're willing and able to alter the source of glut, you're out of luck.
Many C APIs that use callbacks pass a user-specified void* parameter to the callback, which you can use to store a pointer to your class. You can then pass a free function which casts the user data to a class pointer and then calls the member function. However, the way glut is designed doesn't allow that.

Callback to non-static method

Think of your basic GLUT programs. They simply run from a main method and contain callbacks like `glutMouseFunc(MouseButton) where MouseButton is the name of a method.
What I have done is I have encapsulated the main file into a class, so that MouseButton is no longer a static function but has an instance. But doing this gives me a compilation error :
Error 2 error C3867: 'StartHand::MouseButton': function call missing argument list; use '&StartHand::MouseButton' to create a pointer to member c:\users\angeleyes\documents\visual studio 2008\projects\capstone ver 4\starthand.cpp 388 IK Engine
It is not possible to provide a code sample as the class is quite huge.
I have tried using this->MouseButton but that gives the same error. Can't a pointer to an instance function be given for callback?
As the error message says, you must use &StartHand::MouseButton syntax to get a pointer to a member function (ptmf); this is simply mandated as part of the language.
When using a ptmf, the function you are calling, glutMouseFunc in this case, must also expect to get a ptmf as a callback, otherwise using your non-static MouseButton won't work. Instead, a common technique is for callbacks to work with a user-supplied void* context, which can be the instance pointer—but the library doing the callbacks must explicitly allow this parameter. It's also important to make sure you match the ABI expected by the external library (the handle_mouse function below).
Since glut doesn't allow user-supplied context, you have to use another mechanism: associate your objects with glut's current window. It does provide a way to get the "current window", however, and I've used this to associate a void* with the window. Then you simply need to create a trampoline to do the type conversion and call the method.
Machinery:
#include <map>
int glutGetWindow() { return 0; } // make this example compile and run ##E##
typedef std::pair<void*, void (*)(void*,int,int,int,int)> MouseCallback;
typedef std::map<int, MouseCallback> MouseCallbacks;
MouseCallbacks mouse_callbacks;
extern "C" void handle_mouse(int button, int state, int x, int y) {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) { // should always be true, but possibly not
// if deregistering and events arrive
i->second.second(i->second.first, button, state, x, y);
}
}
void set_mousefunc(
MouseCallback::first_type obj,
MouseCallback::second_type f
) {
assert(obj); // preconditions
assert(f);
mouse_callbacks[glutGetWindow()] = MouseCallback(obj, f);
//glutMouseFunc(handle_mouse); // uncomment in non-example ##E##
handle_mouse(0, 0, 0, 0); // pretend it's triggered immediately ##E##
}
void unset_mousefunc() {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) {
mouse_callbacks.erase(i);
//glutMouseFunc(0); // uncomment in non-example ##E##
}
}
Example:
#include <iostream>
struct Example {
void MouseButton(int button, int state, int x, int y) {
std::cout << "callback\n";
}
static void MouseButtonCallback(
void* self, int button, int state, int x, int y
) {
static_cast<Example*>(self)->MouseButton(button, state, x, y);
}
};
int main() {
Example obj;
set_mousefunc(&obj, &Example::MouseButtonCallback);
return 0;
}
Notice that you don't call glutMouseFunc directly anymore; it is managed as part of [un]set_mousefunc.
Just in case it isn't clear: I've rewritten this answer so it should work for you and so that it avoids the C/C++ linkage issue being debated. It will compile and run as-is (without glut), and it should work with glut with only minor modification: comment or uncomment the 4 lines marked ##E##.
No, a pointer to an instance function can not be given to a callback function expecting a function pointer of a certain signature. Their signatures are different. It won't compile.
Generally such APIs allow you to pass in a void* as a "context" parameter. You pass in your object there, and write a wrapper function which takes the context as the callback. The wrapper casts it back to whatever class you were using, and calls the appropriate member function.
You can't replace a static callback with an instance one. When the caller calls your callback, on what instance whoul it call? In other words, how does the caller pass in the formal 'this' argument?
The solution is to have a static callback stub and pass the instance as argument, which implies the callee must accept an arbitrary pvoid that will pass back when invoking the callback. In the stub, you can then call the non-static method:
class C {
void f() {...}
static void F(void* p) {
C* pC = (C*)p;
pC->f();
}
}
C* pC = ...;
someComponent.setCallback(&C::F, pC);
Contrary to what everyone seems to be saying, you most definitely CAN use a non-static member function as a callback method. It requires special syntax designed specifically for getting pointers to non-static members, and special syntax to call that function on a specific instance of a class. See here for a discussion of the needed syntax.
Here is sample code that illustrates how this works:
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;
class Operational
{
public:
Operational(int value) : value_(value) {};
string FormatValue() const ;
private:
int value_;
};
string Operational::FormatValue() const
{
stringstream ss;
ss << "My value is " << value_;
return ss.str();
}
typedef string(Operational::*FormatFn)() const; // note the funky syntax
Operational make_oper(int val)
{
return Operational(val);
}
int main()
{
// build the list of objects with the instance callbacks we want to call
Operational ops[] = {1, 2, 3, 5, 8, 13};
size_t numOps = sizeof(ops)/sizeof(ops[0]);
// now call the instance callbacks
for( size_t i = 0; i < numOps; ++i )
{
// get the function pointer
FormatFn fn = &Operational::FormatValue;
// get a pointer to the instance
Operational* op = &ops[i];
// call the callback on the instance
string retval = (op->*fn)();
// display the output
cout << "The object # " << hex << (void*)op << " said: '" << retval << "'" << endl;
}
return 0;
}
The output of this program when I ran it on my machine was:
The object # 0017F938 said: 'My value is 1'
The object # 0017F93C said: 'My value is 2'
The object # 0017F940 said: 'My value is 3'
The object # 0017F944 said: 'My value is 5'
The object # 0017F948 said: 'My value is 8'
The object # 0017F94C said: 'My value is 13'
You cannot use a non-static member function in this case.
Basically the type of the argument expected by glutMouseFunc is
void (*)(int, int, int, int)
while the type of your non-static member function is
void (StartHand::*)(int, int, int, int)
First problem is that types don't really match.
Second, in order to be able to call that method, the callback would have to know which object ( i.e. "this" pointer ) your method belongs to ( that's pretty much why the types are different in the first place ).
And third, I think you're using the wrong syntax to retrieve the method's pointer. The right syntax should be: &StartHand::MouseButton.
So, you have to either make that method static or use some other static method that would know which StartHand pointer to use to call MouseButton.
The following works in c++ to define a c callback function, useful for example when using glut (glutDisplayFunc, glutKeyboardFunc, glutMouseFunc ...) when you only need a single instance of this class :
MyClass * ptr_global_instance = NULL;
extern "C" void mouse_buttons_callback(int button, int state, int x, int y) {
// c function call which calls your c++ class method
ptr_global_instance->mouse_buttons_cb(button, state, x, y);
}
void MyClass::mouse_buttons_cb(int button, int state, int x, int y) {
// this is actual body of callback - ie. if (button == GLUT_LEFT_BUTTON) ...
// implemented as a c++ method
}
void MyClass::setup_glut(int argc, char** argv) { // largely boilerplate glut setup
glutInit(&argc, argv);
// ... the usual suspects go here like glutInitWindowSize(900, 800); ...
setupMouseButtonCallback(); // <-- custom linkage of c++ to cb
// ... other glut setup calls here
}
void MyClass::setupMouseButtonCallback() {
// c++ method which registers c function callback
::ptr_global_instance = this;
::glutMouseFunc(::mouse_buttons_callback);
}
In your MyClass header we add :
void mouse_buttons_cb(int button, int state, int x, int y);
void setupMouseButtonCallback();
This also works using identical logic flows to setup your glut
call to glutDisplayFunc(display)

C++ Using Class Method as a Function Pointer Type

In a C lib, there is a function waiting a function pointer such that:
lasvm_kcache_t* lasvm_kcache_create(lasvm_kernel_t kernelfunc, void *closure)
where lasvm_kernel_t is defined as:
typedef double (*lasvm_kernel_t)(int i, int j, void* closure);
Now, if I send a method defined in a class to lasvm_kcache_create:
double cls_lasvm::kernel(int i, int j, void *kparam)
...
lasvm_kcache_t *kcache=lasvm_kcache_create(&kernel, NULL);
I get: "cannot convert ‘double (cls_lasvm::)(int, int, void)’ to ‘double ()(int, int, void)’"
What should I do?
I'm assuming that the closure argument is a context 'cookie' for the use of the callback to get appropriate context. This is a acomon idiom for callback functions, and seems to be what's going on based on the snippets you've provided (but I don't know for sure, as I don't know anything about kcache_create() except what you posted here).
You can use that cookie to pass a pointer to the cls_lasvm instance you're dealing with like so:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// have to get a cls_lasvm pointer somehow, maybe the
// void* clpsure is a context value that can hold the
// this pointer - I don't know
cls_lasvm* me = reinterpret_cast<cls_lasvm*>( closure);
return me->kernel( i, j)
}
class cls_lasvm //...
{
...
// the callback that's in the class doens't need kparam
double cls_lasvm::kernel(int i, int j);
};
...
// called like so, assuming it's being called from a cls_lasvm
// member function
lasvm_kcache_t *kcache=lasvm_kcache_create(&lasvm_kcache_create_callback, this);
If I'm wrong about closure being a context cookie, then your callback function in the cls_lasvm class needs to be static:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// if there is no context provided (or needed) then
// all you need is a static function in cls_lasvm
return cls_lasvm::kernel( i, j, closure);
}
// the callback that's in the class needs to be static
static double cls_lasvm::kernel(int i, int j, void* closure);
Note that a C callback function implemented in C++ must be extern "C". It may seem to work as a static function in a class because class-static functions often use the same calling convention as a C function. However, doing that is a bug waiting to happen (see comments below), so please don't - go through an extern "C" wrapper instead.
If closure isn't a context cookie and for some reason cls_lasvm::kernel() can't be static then you need to come up with a way to stash a this pointer somewhere and retrieve that pointer in the lasvm_kcache_create_callback() function, similar to the way I did in my first example, except that pointer has to come dfrom some mechanism you devise yourself. Note that this will likely make using lasvm_kcache_create() non-reentrant and non-threadsafe. That may or may not be a problem depending on your specific circumstances.
Every C++ member function has an implicit, hidden, first parameter, this.
So the method double cls_lasvm::kernel(int i, int j, void* kparam) is really:
double cls_lasvm::kernel(cls_lasvm* this, int i, int j, void* kparam), and it is inappropriate/impossible to use it as a function-pointer parameter.
To make progress, convert your method to be a static-member-method. That will remove the this pointer. You may still have other issues to overcome, but that is a good start.
If it is an external C library whose code you can not modify, then there is not much you can do about it. You'll not be able to call the member function as they require this pointer to work properly (to get the attributes of the object). The easiest workaround, I can think of is using third void* param to pass around this pointer. You can define struct like after defining one more typedef like:
typedef double (cls_lasvm::*lasvm_kernel_t_member)(int i, int j, void* closure);
struct MyParam
{
A* pThis;
lasvm_kernel_t_member pMemFun;
void* kParam;
};
I haven't compiled it, I hope it makes sense.
Then in your class define a static method which receives the call from library:
class cls_lasvm
{
static double test(int i, int j, void *kparam)
{
MyParam* pParam = reinterpret_cast<MyParam*>(kparam);
return (pParam->*pMemFun)(i,j,pParam->kParam);
}
};
While calling you should use something like:
cls_lasvm a;
MyParam param;
param.pThis = &a;
param.pMemFun = &cls_lasvm::kernel;
param.kParam = NULL;
lasvm_kcache_create(&cls_lasvm::test,&a);