Function pointers for thread communication

When you program with thread objects (a thread bound to a class instance) in C++ you inevitably run into the need for an effective way of extracting information from them. At this point the dilemma becomes; do you ask the thread for the information or do you get the thread to report it to you? Both approaches are valid within the right context but there are a number of situations where it is more useful to have a thread object report something to you rather than explicitly asking it. One example of this is to have the thread object report to error handling if it fails for some reason. The temptation here can be to poll the thread object to see if it is still ok, this is the wrong approach no matter how it is implemented. It is far better to assume that everything is ok unless you are told differently, simply put; don't ask, be told.

…use of function pointers to communicate in this way is flexible and powerful

So we want a thread object to be able to tell us something, but how do we go about structuring that communication? The answer is with function pointers. Very briefly; a function pointer allows a client who possesses it to call the function that is bound to it. The important thing here is that the client doesn't need to know what function is being called. This is perfect for the situation where a thread object wants to report something. A client makes a custom function and gives it to the thread to be called under whatever circumstances are appropriate. The use of function pointers to communicate in this way is flexible and powerful and can be adapted to whatever situation you find yourself in.

Making a Simple Timer

Now obviously we need a concrete example to show the technique in action. For this I have picked a problem that the technique solves elegantly; a timer. The concept of a timer is simple; after a given amount of time a client wants to be notified that the amount of time has elapsed. It's a simple idea but it does require threads to implement properly, and it is a situation where polling would be the antithesis of correct design. The solution is to give the timer object a function pointer which it executes when the specified amount of time has expired.

As always the code example uses some of the boost libraries, you can find it here and it should be used as a reference while reading the rest of the tutorial.

The code example includes a main.cpp and is runnable. Running it produces the following output:

Zzzz...
Zzzz...
Buzz!!!
Zzzz...
Buzz!!!
Zzzz...
Zzzz...
Zzzz...
Zzzz...
Zzzz...

What happens is the program creates two timers; one for three seconds and the other for five seconds and when the timers expire they call their function pointer which prints “Buzz!!” to standard out. Meanwhile the main thread loops for ten seconds printing “Zzzz...” every second a timer has not expired. The main() file is very simple and is shown below in it's entirety:


#include "Timer.hpp"

#include "boost/date_time.hpp"
#include "boost/thread.hpp"
#include "boost/bind.hpp"

#include <iostream>

namespace
{
  void timerExpired()
  {
    std::cout << "Buzz!!!" << std::endl;
  }

} // namespace

int main(int c, char** argv)
{
  Timer threeSecondTimer( boost::posix_time::seconds(3),
                         boost::bind(&::timerExpired) );
  Timer fiveSecondTimer( boost::posix_time::seconds(5),
                         boost::bind(&::timerExpired) );

  for (int i=1; i<=10; ++i)
  {
    boost::this_thread::sleep(boost::posix_time::seconds(1));
    if (i == 3 || i == 5)
      continue;
    std::cout << "Zzzz..." << std::endl;
  }

} // main

Note the use of Boost.Bind here to create the function pointers given to the timers, Boost.Bind is THE way you should be creating function pointers. Check out my tutorial on boost bind if you haven't heard of or used it before.

The interesting part of the code is the timer class itself, which builds upon the thread class object described in one of my earlier tutorials. The timer adds little to the thread class, so little in fact that I can show you all the pertinent parts quickly below.


void Timer::threadMain()
{
  try
  {
    boost::this_thread::sleep( timeToWait_ );
    reportingCallback_();

The threadMain function is very simple, just a sleep and then hit the function pointer... and that's all the pertinent parts! There is more framework code here but as stated previously it is all covered in my thread class tutorial check it out if you want more insight into the rest of the code.

Without picking over the code in detail it should be obvious the role that the function pointers passed to the timers play. The
timerExpired()
function could be replaced with any function with the same signature without the timer class having to be changed and this makes the reporting customisable to the needs of any client.

Beware of Concurrency Issues

One thing to be aware of when using this idiom is that when the function pointer is called it is the thread in the Timer object that does the execution. Now this should be obvious but is not always to the uninitiated. The ramifications of this is that special attention needs to be paid to the reporting function with regard to concurrency.

Imagine that in main instead of two timers a thousand were created and all with a duration of one second. All of the timers would report at the same time to the same function all printing to standard out. As iostreams are not thread safe you would get an interleaving of characters from all of the “Buzz!!”'s which would be horribly messy. This is a basic concurrency concept to be familiar with and could be effectively solved through the use of 'mutual exclusion' in the form of a mutex, however the usage of mutexes is beyond the scope of this tutorial.

Now the example given is a very simple case and easily fixed, but things can become much more problematic depending upon the complexity of the reporting function and it's integration with the rest of the program. So be warned and be aware of this potential pitfall.

Extending the Concept

Using function pointers as a means of receiving information from threads is a powerful and flexible technique. The example shown here is basic but you should be able to take the concept and run with it to whatever place you need it to go. The only caveat is that, as always, when using threads be very aware of possible concurrency issues that may emerge.

Leave a Comment