I’ve got an OOP / design problem that I have run into and am desperately hoping that someone can steer me in a direction that doesn’t require a complete re-write.
The system is essential a Windows Service that have ~9 secondary threads that are responsible for specific tasks. All the threads share some common functionality (for example, the ability to send and receive messages internally etc). Because of this, I defined an abstract base class from which all the threads inherit from.
However, four of the threads also make use of an Inter-Process communication system based on a 3rd-party IPC system (madshi’s CreateIpcQueue ). To save replicating all the same code in these four threads, I defined an additional class to support this:
TThread <-TBaseThread<-TIPCBaseThread<- Four IPC threads
^- All other threads.
The mechanics of the IPC system is that you define a Callback function and then call the CreateIpcQueue passing it this Callback. In my TIPCBaseThread I loosely did something like this:
// TIPCBaseThread.h
class TIPCBaseThread : public TBaseThread
{
private:
static TIPCBaseThrd *pThis;
// defines the callback to use with the IPC queue
static void CALLBACK IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen,
void *pRtnBuf, unsigned int iRtnLen);
protected:
// virtual method, to be defined in derived classes, to handle IPC message
virtual void ProcessIPCMsg(char *cName, void *pMsgBuf, unsigned int iMsgLen, void *pRtnBuf,
unsigned int iRtnLen) = 0;
public:
CRITICAL_SECTION csIPCCritSect;
…
// TIPCBaseThread.cpp
TIPCBaseThrd* TIPCBaseThrd::pThis = 0;
__fastcall TIPCBaseThread::TIPCBaseThread(…) : TBaseThread(…)
{
pThis = this;
InitializeCriticalSectionAndSpinCount(&csIPCCritSect, 1000);
CreateIpcQueueEx(“SomeQueueName”, IPCQueue, 1, 0x1000);
//^Callback Queue
…
}
void CALLBACK TIPCBaseThread::IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen,
void *pRtnBuf, unsigned int iRtnLen)
{
EnterCriticalSection(&pThis->csIPCCritSect);
pThis->ProcessIPCMsg(cName, pMsgBuf, iMsgLen, pRtnBuf, iRtnLen);
LeaveCriticalSection(&pThis->csIPCCritSect);
}
My general thinking was that the TIPCBaseThread would effectively take care of creating and managing the IPC channel and then call the ProcessIPCMsg() in the various derived classes.
Now, when I test the system and send a message to any of the IPC channels, the message is received in the TIPCBaseThread callback but is passed up to the last derived class (to be created), not the class that should receive it. I’m assuming it is something to do with the
[static TIPCBaseThrd *pThis]
property being overwritten when each derived class is instantiated (but I confess I’m not 100% sure)?
Could anyone steer me in the right direction here? Obviously I would like to know exactly what is causing the problem but ideally I would like to know if there is a work around that would avoid having to completely re-write the whole object inheritance – there is obviously a bit more going on under the hood than I have shown and I’m going to have serious problems if I have to abandon this design completely.
Many thanks in advance,
Mike Collins
I think you should change the callback to take the instance as an argument
static void CALLBACK IPCQueue(TIPCBaseThread *instance,
char *cName, void *pMsgBuf, unsigned int iMsgLen,
void *pRtnBuf, unsigned int iRtnLen);
...
void CALLBACK TIPCBaseThread::IPCQueue(char *cName, void *pMsgBuf, unsigned int iMsgLen,
void *pRtnBuf, unsigned int iRtnLen)
{
...
instance->ProcessIPCMsg(cName, pMsgBuf, iMsgLen, pRtnBuf, iRtnLen);
...
}
There is one very strange thing: pThis = this; with static TIPCBaseThrd *pThis;
It means that at any point in time only the latest instance of TIPCBaseThrd is accessible via pThis (all previous instances having been overwritten); and of course there is the issue that this global value is not protected by any kind of synchronisation (mutex, atomics, ...)
It's unfortunate, but this static TIPCBaseThrd *pThis; is just an horrible idea that cannot possibly work.
Related
In order to implement a thread class(In C++98 and Windows.h). I have something like this:
Thread::Thread(_beginthreadex_proc_type fn)
{
m_raw = fn;
m_args = 0;
m_handle = 0;
m_id = 0;
}
The code above works fine it takes a function that not receive parameters, and with the next code it function is called by a new thread:
void Thread::Join()
{
m_handle = (HANDLE)_beginthreadex(0, 0, m_raw, (m_args ? m_args : 0), 0, 0);
if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}
This code also works fine with functions that don't take any parameter.
Now my question is about how can i in C++98 receive variadic parameters in my constructor and save them.
And NO i can't use modern c++ if that was the case I din't need help. So plz don't give me solutions implemented with c++11 or higher.
Update
Now I'm trying a Java style solution in that every Thread is a IRunnable that have a pure virtual function named Run. And thread is almost the that this implementetation with the diff that is an abstract class. In this way can i avoid parameters because I don't pass the function instead of that I write another class that inherits from Thread and implements Run.
The code look like:
The interface
struct IRunnable
{
virtual void Run() = 0;
};
Thread class
class Thread : public IRunnable
{
HANDLE m_handle;
DWORD m_id;
typedef unsigned (__stdcall *Function)(void*);
_beginthreadex_proc_type m_raw;
void* m_args;
public:
Thread();
~Thread();
Thread(_beginthreadex_proc_type, void*);
Thread(_beginthreadex_proc_type);
unsigned GetId();
virtual void Run() = 0;
void Join();
unsigned int __stdcall call(void*);
};
Call only is a wrapper to call Run function member
unsigned int __stdcall Thread::call(void* data)
{
Run();
return 0;
}
My problem is here:
void Thread::Join()
{
m_handle = (HANDLE)_beginthreadex(0, 0, &this->call, 0, 0, 0);
if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}
When i compiling in vs2019 the code above produce the next error:
error C2276: '&': illegal operation on bound member function expression
error C2660: '_beginthreadex': function does not take 5 arguments
For your edited question, the reason you're getting a compile error is because you're trying to send the address to a member function of your Thread object. You can't take pointers to member functions and use them without also keeping the object pointer around. Instead, you should make a global function that takes a Thread* as its argument, send a pointer to that function, and let it call your runnable.
unsigned thread_entry(void* thread_ptr)
{
Thread* thread = (Thread*) thread_ptr;
return thread->call();
}
void Thread::Join()
{
m_handle = (HANDLE)_beginthreadex(0, 0, thread_entry, this, 0, 0);
if (m_handle) WaitForSingleObject(m_handle, INFINITE);
}
P.S. It's usually best to ask new questions instead of editing old ones if the question is significantly different, which yours is.
If you look at pretty much any thread library, they very rarely support sending multiple arguments; you usually send a pointer to something, and if you want many things, you make a struct containing many things and send a pointer to it.
However, if you really want this, you could use the C varargs functions to iterate over all variadic arguments, and allocate a linked list with them, or allocate an array of them, or whatever other data structure you want. Then, send a pointer to that to your thread entry function. Your function would still be taking just one pointer, though.
In C, there is no easy way to construct a va_list, which is how variadic arguments are sent around. You can't just send the va_list you have on your main thread, because that memory won't be alive by the time it reaches your new thread. There is also no good way to expand a va_list to fill function arguments.
Btw, I realize you're using C++, but as far as C++98 goes, its varargs support is basically the same as in C, which is why I'm mentioning C in my answer.
I need your help with wxWidgets. I have 2 threads (1 wxTimer and 1 wxThread), I need communicate between this 2 threads. I have a class that contains methods to read/write variable in this class. (Share Memory with this object)
My problem is: I instanciate with "new" this class in one thread but I don't know that necessary in second thread. Because if instanciate too, adress of variable are differents and I need communicate so I need even value in variable :/
I know about need wxSemaphore to prevent error when to access same time.
Thanks you for your help !
EDIT: My code
So, I need make a link with my code. Thanks you for all ;)
It's my declaration for my wxTimer in my class: EvtFramePrincipal (IHM)
In .h
EvtFramePrincipal( wxWindow* parent );
#include <wx/timer.h>
wxTimer m_timer;
in .cpp -Constructor EvtFramePrincipal
EvtFramePrincipal::EvtFramePrincipal( wxWindow* parent )
:
FramePrincipal( parent ),m_timer(this)
{
Connect(wxID_ANY,wxEVT_TIMER,wxTimerEventHandler(EvtFramePrincipal::OnTimer),NULL,this);
m_timer.Start(250);
}
So I call OnTimer method every 250ms with this line.
For my second thread start from EvtFramePrincipal (IHM):
in .h EvtFramePrincipal
#include "../Client.h"
Client *ClientIdle;
in .cpp EvtFramePrincipal
ClientIdle= new Client();
ClientIdle->Run();
In .h Client (Thread)
class Client: public wxThread
public:
Client();
virtual void *Entry();
virtual void OnExit();
In .cpp Client (Thread)
Client::Client() : wxThread()
{
}
So here, no probleme, thread are ok ?
Now I need that this class that use like a messenger between my 2 threads.
#ifndef PARTAGE_H
#define PARTAGE_H
#include "wx/string.h"
#include <iostream>
using std::cout;
using std::endl;
class Partage
{
public:
Partage();
virtual ~Partage();
bool Return_Capteur_Aval()
{ return Etat_Capteur_Aval; }
bool Return_Capteur_Amont()
{ return Etat_Capteur_Amont; }
bool Return_Etat_Barriere()
{ return Etat_Barriere; }
bool Return_Ouverture()
{ return Demande_Ouverture; }
bool Return_Fermeture()
{ return Demande_Fermeture; }
bool Return_Appel()
{ return Appel_Gardien; }
void Set_Ouverture(bool Etat)
{ Demande_Ouverture=Etat; }
void Set_Fermeture(bool Etat)
{ Demande_Fermeture=Etat; }
void Set_Capteur_Aval(bool Etat)
{ Etat_Capteur_Aval=Etat; }
void Set_Capteur_Amont(bool Etat)
{ Etat_Capteur_Amont=Etat; }
void Set_Barriere(bool Etat)
{ Etat_Barriere=Etat; }
void Set_Appel(bool Etat)
{ Appel_Gardien=Etat; }
void Set_Code(wxString valeur_code)
{ Code=valeur_code; }
void Set_Badge(wxString numero_badge)
{ Badge=numero_badge; }
void Set_Message(wxString message)
{
Message_Affiche=wxT("");
Message_Affiche=message;
}
wxString Get_Message()
{
return Message_Affiche;
}
wxString Get_Code()
{ return Code; }
wxString Get_Badge()
{ return Badge; }
protected:
private:
bool Etat_Capteur_Aval;
bool Etat_Capteur_Amont;
bool Etat_Barriere;
bool Demande_Ouverture;
bool Demande_Fermeture;
bool Appel_Gardien;
wxString Code;
wxString Badge;
wxString Message_Affiche;
};
#endif // PARTAGE_H
So in my EvtFramePrincipal(wxTimer), I make a new for this class. But in other thread (wxThread), what I need to do to communicate ?
If difficult to understand so sorry :/
Then main thread should create first the shared variable. After it, you can create both threads and pass them a pointer to the shared variable.
So, both of them, know how interact with the shared variable. You need to implement a mutex or wxSemaphore in the methods of the shared variable.
You can use a singleton to get access to a central object.
Alternatively, create the central object before creating the threads and pass the reference to the central object to threads.
Use a mutex in the central object to prevent simultaneous access.
Creating one central object on each thread is not an option.
EDIT 1: Adding more details and examples
Let's start with some assumptions. The OP indicated that
I have 2 threads (1 wxTimer and 1 wxThread)
To tell the truth, I know very little of the wxWidgets framework, but there's always the documentation. So I can see that:
wxTimer provides a Timer that will execute the wxTimer::Notify() method when the timer expires. The documentation doesn't say anything about thread-execution (although there's a note A timer can only be used from the main thread which I'm not sure how to understand). I can guess that we should expect the Notify method will be executed in some event-loop or timer-loop thread or threads.
wxThread provides a model for Thread execution, that runs the wxThread::Entry() method. Running a wxThread object will actually create a thread that runs the Entry method.
So your problem is that you need same object to be accessible in both wxTimer::Notify() and wxThread::Entry() methods.
This object:
It's not one variable but a lot of that store in one class
e.g.
struct SharedData {
// NOTE: This is very simplistic.
// since the information here will be modified/read by
// multiple threads, it should be protected by one or more
// mutexes
// so probably a class with getter/setters will be better suited
// so that access with mutexes can be enforced within the class.
SharedData():var2(0) { }
std::string var1;
int var2;
};
of which you have somewhere an instance of that:
std::shared_ptr<SharedData> myData=std::make_shared<SharedData>();
or perhaps in pointer form or perhaps as a local variable or object attribute
Option 1: a shared reference
You're not really using wxTimer or wxThread, but classes that inherit from them (at least the wxThread::Entry() is pure virtual. In the case of wxTimer you could change the owner to a different wxEvtHandler that will receive the event, but you still need to provide an implementation.
So you can have
class MyTimer: public wxTimer {
public:
void Notify() {
// Your code goes here
// but it can access data through the local reference
}
void setData(const std::shared_ptr<SharedData> &data) {
mLocalReference=data
}
private:
std::shared_ptr<SharedData> mLocalReferece
};
That will need to be set:
MyTimer timer;
timer.setData(myData);
timer.StartOnece(10000); // wake me up in 10 secs.
Similarly for the Thread
class MyThread: public wxThread {
public:
void Entry() {
// Your code goes here
// but it can access data through the local reference
}
void setData(const std::shared_ptr<SharedData> &data) {
mLocalReference=data
}
private:
std::shared_ptr<SharedData> mLocalReferece
};
That will need to be set:
MyThread *thread=new MyThread();
thread->setData(myData);
thread->Run(); // threads starts running.
Option2 Using a singleton.
Sometimes you cannot modify MyThread or MyTimer... or it is too difficult to route the reference to myData to the thread or timer instances... or you're just too lazy or too busy to bother (beware of your technical debt!!!)
We can tweak the SharedData into:
struct SharedData {
std::string var1;
int var2;
static SharedData *instance() {
// NOTE that some mutexes are needed here
// to prevent the case where first initialization
// is executed simultaneously from different threads
// allocating two objects, one of them leaked.
if(!sInstance) {
sInstance=new SharedData();
}
return sInstance
}
private:
SharedData():var2(0) { } // Note we've made the constructor private
static SharedData *sInstance=0;
};
This object (because it only allows the creation of a single object) can be accessed from
either MyTimer::Notify() or MyThread::Entry() with
SharedData::instance()->var1;
Interlude: why Singletons are evil
(or why the easy solution might bite you in the future).
What is so bad about singletons?
Why Singletons are Evil
Singletons Are Evil
My main reasons are:
There's one and only one instance... and you might think that you only need one now, but who knows what the future will hold, you've taken an easy solution for a coding problem that has far reaching consequences architecturally and that might be difficult to revert.
It will not allow doing dependency injection (because the actual class is used in the accessing the object).
Still, I don't think is something to completely avoid. It has its uses, it can solve your problem and it might save your day.
Option 3. Some middle ground.
You could still organize your data around a central repository with methods to access different instances (or different implementations) of the data.
This central repository can be a singleton (it is really is central, common and unique), but is not the shared data, but what is used to retrieve the shared data, e.g. identified by some ID (that might be easier to share between the threads using option 1)
Something like:
CentralRepository::instance()->getDataById(sharedId)->var1;
EDIT 2: Comments after OP posted (more) code ;)
It seems that your object EvtFramePrincipal will execute both the timer call back and it will contain the ClientIdle pointer to a Client object (the thread)... I'd do:
Make the Client class contain a Portage attribute (a pointer or a smart pointer).
Make the EvtFramePrincipal contain a Portage attribute (a pointer or smart pointer). I guess this will have the lifecycle of the whole application, so the Portage object can share that lifecycle too.
Add Mutexes locking to all methods setting and getting in the Portage attribute, since it can be accessed from multiple threads.
After the Client object is instantiated set the reference to the Portage object that the EvtFramePrincipal contains.
Client can access Portage because we've set its reference when it was created. When the Entry method is run in its thread it will be able to access it.
EvtFramePrincipal can access the Portage (because it is one of its attributes), so the event handler for the timer event will be able to access it.
I'am writing small class for RS232 port. It can sync write and async read. So, for async read I'm using second thread, that waiting input data. When data received, I want to call user callback (that I get as constructor argument) with input data. It's look like:
typedef int (*ReceivedCallback)(string data);
class RS232
{
RS232(string portName, ReceivedCallback dataReceived);
~RS232();
private:
ReceivedCallback dataReceivedCallback;
private:
static unsigned ReaderThread(void* data);
public:
SendData(string data);
}
My problem is: ReaderThread MUST be static to pass pointer to it to _beginthreadex() function. And in ReaderThread I want to call "dataReceivedCallback", obtained from the user in constructor. But I can't, cause I can't call non-static functions in static ReaderThread. Also, I can't make "dataReceivedCallback" static, cause I may have many instances of my class (for COM1, COM2, COM3) and every instance should have it's own callback, obtained by user.
Where is my architecture mistake? How would you implement it?
Thanks in advance!
P.S. Using Visual Studio 2005.
You need to pass a pointer to the instance of RS232 to ReaderThread, which will, in turn, either pass that pointer to a static callback, or directly call non-static methods on the RS232 object.
I would also use [CreateThread][1] rather than beginthreadex. My code samples will use CreateThread, but you can adapt the technique to beginthreadex if you so desire.
Simply, when kicking off the ReaderThread, pass it a pointer to the instance:
RS232* myObj = new RS232;
CreateThread (..., myObj);
...use reinterpret_cast to cast it back:
unsigned RS232::ReaderThread (void* data)
{
RS232* that = reinterpret_cast <RS232*> (data);
}
Change your callback function so that it can pass the instance as well:
typedef int (*ReceivedCallback)(string data, RS232* that);
And now in the callback you can call member functions:
that->DoSomethingCool (data);
You will need to pass an extra argument to the thread function (which you already have a void *data available for).
Now, add this as a private element in your class RS232:
class RS232
{
RS232(string portName, ReceivedCallback dataReceived);
~RS232();
private:
ReceivedCallback dataReceivedCallback;
private:
static unsigned ReaderThread(void* data);
public:
SendData(string data);
}
and in the constructor:
RS232::RS232(string portName, ReceivedCallback dataReceived)
{
... various stuff to initialize the serial port ...
_beginthreadex(securityarg, stacksize, ReaderThread, this, ...)
}
And in the ReaderThread function:
unsigned RS232::ReaderThread(void *data)
{
RS232 *self = static_cast<RS232*>(data);
.... stuff to read from serial port ...
... Now call the callback:
self->dataReceivedCallback(str);
....
}
To access the non-static object data in the static thread function you could use this extremely hacky and untested solution. But be warned --- it is for educational purposes only because it is extremely hacky. You should learn about locks and mutexes and probably boost threads. Note, this is a pthread style solution. I've no experience with the function _beginthreadex() but you can see that createThread does the job of creating your thread. Adapt as needed.
typedef int (*ReceivedCallback)(string data);
class RS232
{
public:
RS232(string portName, ReceivedCallback dataReceived);
~RS232();
SendData(string data);
createThread();
private:
ReceivedCallback dataReceivedCallback;
static unsigned ReaderThread(void* data);
thread m_someThread;
struct accessHelper
{
RS232* This;
void *actual_arg;
accessHelper(RS232 *t, void *p)
: This(t),
actual_arg(p)
{}
};
};
RS232::createThreaad()
{
int someData;
accessHelper ah(this, someData);
m_someThread.create(RS232::ReaderThread, &ah);
}
RS232::ReaderThread(void *data)
{
accessHelper *ah = static_cast<accessHelper*>(data);
RS232 *This = ah->This;
This->dataReceivedCallback......
}
Some background for this question is my previous question:
non-member function pointer as a callback in API to member function (it may well be irrelevant).
The callback launches a thread that writes some data. There is another thread that reads the same data, and that results in some crashes.
I just took a crash course in multi-threading (thanks SO), and here is my attempt to guarantee that the data isn't accessed by the writer and the reader at the same time. I'm using some mutex mechanism from Qt (QReadWriteLock).
#include <QSharedPointer>
#include <QReadWriteLock>
Class MyClass
{
public:
MyClass();
bool open();
float getData();
void streamCB(void* userdata);
protected:
float private_data_;
QSharedPointer<QReadWriteLock> lock_;
};
// callback wrapper from non-member C API to member function void
__stdcall streamCBWrapper(void* userdata)
{
static_cast<MyClass*>(userdata)->streamCB(userdata);
}
// constructor
MyClass::MyClass()
{
lock_ = QSharedPointer<QReadWriteLock>(new QReadWriteLock());
lock_->lockForWrite();
private_data_ = getData();
lock_->unlock();
}
// member callback
void MyClass:streamCB(void* userdata)
{
float a = getData();
lock_->lockForWrite(); //*** fails here
private_data_ = a;
lock_->unlock();
}
I have a segmentation fault while running the program. The VS debugger says Access violation writing location 0x00fedbed. on the line that I marked //*** fails here.
The lock worked in the constructor, but not in the callback.
Any idea what goes wrong? What should I look at? (and how can I refine my question)
Thanks!
Other relevant thread
Cannot access private member declared in class 'QReadWriteLock'Error 1 error C2248: 'QReadWriteLock::QReadWriteLock' (I used the QSharedPointer suggestion)
Edit 1:
The callback is set up
bool MyClass::open()
{
// stuffs
int mid = 0;
set_stream_callback(&streamCBWrapper, &mid);
// more stuffs
return true;
}
Edit 2:
Thank you for all the suggestions.
So my mistake(s) may not be due at all to the mutex, but to my lack of understanding of the API? I'm quite confused.. Here is the API doc for the set_stream_callback.
typedef void (__stdcall *STREAM_CALLBACK)(void *userdata);
/*! #brief Register a callback to be invoked when all subscribed fields have been updated
*
* #param streamCB pointer to callback function
* #param userdata pointer to private data to be passed back as argument to callback
* #return 0 if successful, error code otherwise
*/
__declspec(dllimport) int __stdcall set_stream_callback(
STREAM_CALLBACK streamCB, void *userdata);
Good example why sufficient code example is required.
If I interpret your callback syntax correctly,
set_stream_callback(&streamCBWrapper, &mid);
sets streamCBWrapper as callback function, while &mid is the pointer to userdata.
In the callback, you are actually now casting a pointer to int to MyClass, then try to access a member variable of a non-existant object.
Make sure to pass an instance of MyClass to your callback. I assume this would be this in your case.
Sounds fundamentally like a threading issue to me. Since you're using the Qt mutexing anyway, you might consider using Qt's threading mechanisms and sending signals and slots between the threads. They're pretty well documented and easy to use as long as you follow the suggestions here and here.
I am writing a program, the bulk of which is platform independent code compiled as a static library. I am then writing a program using any specific platform apis which is linked to the static library. Calling functions in the library from the actual program is obviously easy, however I am unsure of the best way (most efficient / cleanest implementation) of communicating with the program from the library.
I have looked into a signals / slots method however I am worried about the performance (ideally some draw calls would go through this). Otherwise the only other method I can think of is some form of callbacks using functors implementation, which should be quicker but is this the best design?
EDIT: My main aims / requirements is performance and easily implementable. The library is written in C++ and already uses boost so boost signals are a possibility, but is their performance acceptable?
Here are your options from (roughly) most flexible to least:
Signals & slots
Several signals and slots implementations are listed here (notably Boost.Signal). These are useful to implement the Observer design pattern where more than one object is interested in receiving notifications.
Boost.Function
You can register a boost::function callback. boost::function is wrapper around any callable entity: free function, static function, member function, or function object. To wrap a member function, you use boost::bind as shown in this example. Usage example:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function<void (void)> MouseCallback;
class Mouse
{
public:
void registerCallback(MouseCallback callback) {callback_ = callback;}
void notifyClicked() {if (callback_) callback_();}
private:
MouseCallback callback_;
};
class Foo
{
public:
void mouseClicked() {std::cout << "Mouse clicked!";}
};
int main()
{
Mouse mouse;
Foo foo;
mouse.registerCallback(boost::bind(&Foo::mouseClicked, &foo));
mouse.notifyClicked();
}
Fast Delegate
There is a delegate implementation, called FastDelegate that is faster than boost::function. It uses an "ugly hack" that is not supported by the C++ standard, but is supported by practically all compilers.
There is also The Impossibly Fast C++ Delegates that is supported by the standard, but not by all compilers.
"Listener" interfaces (abstract classes)
As c-smile suggested, you can register a pointer to an object derived from a callback interface (abstract class). This is the traditional Java way of doing callbacks. Example:
class MouseInputListener
{
public:
virtual void mouseClicked() = 0;
virtual void mouseReleased() = 0;
};
class Mouse
{
public:
Mouse() : listener_(0) {}
void registerListener(MouseInputListener* listener) {listener_ = listener;}
void notifyClicked() {if (listener_) listener_->mouseClicked();}
void notifyReleased() {if (listener_) listener_->mouseReleased();}
private:
MouseInputListener* listener_;
};
class Foo : public MouseInputListener
{
public:
virtual void mouseClicked() {cout << "Mouse clicked!";}
virtual void mouseReleased() {cout << "Mouse released!";}
};
C-style callbacks
You register a pointer to a callback free function, plus an additional "context" void pointer. In the callback function, you cast the void* to the object type that will handle the event, and invoke the proper method. For example:
typedef void (*MouseCallback)(void* context); // Callback function pointer type
class Mouse
{
public:
Mouse() : callback_(0), context_(0) {}
void registerCallback(MouseCallback callback, void* context = 0)
{callback_ = callback; context_ = context;}
void notifyClicked() {if (callback_) callback_(context_);}
private:
MouseCallback callback_;
void* context_;
};
class Foo
{
public:
void mouseClicked() {cout << "Mouse clicked!";}
static void callback(void* context)
{static_cast<Foo*>(context)->mouseClicked();}
};
int main()
{
Mouse mouse;
Foo foo;
mouse.registerCallback(&Foo::callback, &foo);
mouse.notifyClicked();
}
Benchmarks
I have found some performance benchmarks:
http://www.ce.unipr.it/~medici/boostbenchmark.html
http://www.kbasm.com/cpp-callback-benchmark.html
They should give you an idea of what callback mechanism is appropriate.
As you can see by the numbers, you have to be invoking Boost signals 10,000 to 100,000 of times per second before performance even becomes an issue.
My Recommendation
If callbacks will not be invoked at a blazingly high rate (10-100 thousand times per second), then use boost::signal for maximum flexibility and automatic connection lifetime management.
If callbacks will be invoked at an extremely high rate, then start with boost::function for maximum flexibility and portability. It that's still too slow, then go with FastDelegate, or C-style callbacks.
Interfaces (abstract classes). Library expose interfaces. And accept callback interfaces to be invoked from library code. Time proven classic. Why to invent anything else?