[Dar-libdar_api] Re: callback function context value
For full, incremental, compressed and encrypted backups or archives
Brought to you by:
edrusb
|
From: Denis C. <den...@fr...> - 2004-04-27 21:10:28
|
Johnathan Burchill wrote:
> Hi Denis,
Hello Johnathan,
>
> Apparently it is standard coding practice for API callback functions to
> accept a "context value", which is a void *, that allows one to use a
> class member function as a callback without resorting to a global
pointer
> variable.
Well, to my point of view, after having read the tutorial you give
reference bellow, there is no standard coding practice that speaks about
a "context value" for callback. The "context value" is used as a trick
to make a callback function pointing to non-static member functions of a
C++ class. The trick implies a static method or normal function to
explicitely pass the "this" pointer (pointer to the current object which
is a hidden argument in C++) as explicit argument.
Now my question, is do we need libdar calling a non-static member of a
given object (as callback) ?
First there is a risk, if this objects dies, we will have big problems
like memory violations. But OK, if you give a wrong argument as address
of the callback function we get to the same point.
Second, libdar would always call the method of the same object, and it
would require first, a way for kdar (for example) to tell libdar which
object address (the "this" argument) to give to the callback function in
the "context value".
Third, logically, it is a class defined in the user application like
kdar, and libdar does not know anything about this class. This would not
be very useful to libdar point of view.
>
> As I understand dar, it uses a regular function as the callback.
Could you
> add perhaps a new set of callback setting functions to the libdar API
that
> accept a void * context value to be passed. It would be easy to keep
> backwards compatibility with earlier libdar versions by redefining the
> standard callback setting functions to call the new ones with NULL
for the
> void *.
Yes, this is still possible.
I think the need behind is the thread safe libdar library. If the
library is thread safe, there must not be a function in the API that
receive the address of a callback function without any context.
Let's take an example:
actually (version 2.1.2 is the last release) libdar API proposes the
following function:
set_warning_callback(&my_warning_callback);
to reach thread safe level, set_warning_callback must have a contextual
argument, to have a thread discriminant, the callback function stays the
same. In my idea actually, a possible solution is a new class that will
gather all static variables that currently make the libdar thread
unsafe. I have not yet a name for that class, so let's call it 'junk'
for now. We would then have set_warning_callback a method of the 'junk'
class, and probably any other functions of the current API (op_create, etc.)
Before anything else, each thread should create its own 'junk' object
forcing the calling application to give a thread specific callback
function in the 'junk' constructor.
OK now, I see, if you have several threads, you could give several
callback functions (one per thread), but that could lead to some
ineficiency, you could rather give the same callback function to all
thread and have an additional argument in the callback prototype that
tell this common callback function which thread it is called from, and
which action to do (which object to call, etc...). A void pointer should
be effectively interesting as it could carry the address to a function
or the address to an object which method to call.
we would have someting like this:
class junk
{
public:
set_warning_callback(void (*callback)(const std::string &x,
void *context) )
{ warning_callback = callback; };
set_warning_callback_context_to_give(void *context)
{ context_to_give = context; };
op_create(....);
op_create_noexcept(...);
[...]
private:
void *context_to_give;
void (*warning_callback)(const std::string &x, void *context);
};
and inside a give thread :
...
junk toto;
toto.set_warning_callback(&mycallback);
toto.set_warning_context_to_give(this);
toto.op_create_noexcept(...);
...
with the global callback function:
void mycallback(const std::string &x, void *context)
{
context->some_method(x);
// well, this is much simplified.
}
Does this makes sens to you ?
>
> There is a good tutorial at
> http://www.function-pointer.org/callback.html
> #3: How to Implement Callbacks in C and C++
>
> In the examples given, I currently use method B, but it would be
better to
> use method A to avoid using the global variable.
I agree, I dislike global variables.
>
> Cheers,
> JB
>
Cheers,
Denis.
P.S.: the sample code are not expected to compile, there are here for
further reference if necessary.
|