boost.png (6897 bytes) Home Libraries People FAQ More

PrevUpHomeNext

Tutorial

In the following example we create a future which will calculate the factorial of 15. The constructor of the future spawns a new thread which will evaluate fac(15). During the evaluation of fac(15) we can use the main thread to do other things, like e.g. printing fac(1). On calling the function call operator on the future, the future blocks until the other thread finishes.

#include <iostream>
#include <boost/bind.hpp>
#include <boost/futures.hpp>

using namespace std;
using namespace boost::futures;
using namespace boost;

/*
 * fac function for testing
 */
int fac(int n){
  if(n == 0)
    return 0;
  if(n == 1)
    return 1;
  sleep(1);
  return n * fac(n - 1);
}

int main(int argc, char **argv){
  // creates future, spawns new thread and returns immediately
  future<int> f = bind(fac, 15);

  cout << fac(1) << endl;
  cout << "going to wait for result ..." << endl;
  //blocking call; waits for fac(15) to finish
  cout << f() << endl;

  return 1;
}

Sometimes we want to execute several different implementations of the same function in parallel but are only interested in the result of the fastest implementation.

In this example we have a fast_fac function which uses the traditional implementation of the faculty and a disk_based_fac function which uses a large table on the hard-disk with pre-calculated values. For large values the disk-based version may be faster, but it is hard to predict. In this case we start two futures and simply wait for the first to finish. To combine both futures we use the | operator which creates a new future which returns as soon as one of the two given futures returns.

#include <cstdio>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/futures.hpp>

using namespace std;
using namespace boost::futures;
using namespace boost;

/*
 * fac function for testing
 */
int fast_fac(int n){
  if(n == 0)
    return 0;
  if(n == 1)
    return 1;
  return n * fac(n - 1);
}

int disk_based_fac(int n){
  int result;
  FILE *f = fopen("fac_table.dat");
  int error = fseek(f, n * sizeof(int), SEEK_SET);
  error = fread(&result, sizeof(int), 1, f);
  error = fclose(f);
  return result;
}

int main(int argc, char **argv){
  // creates future, spawns new thread and returns immediately
  future<int> f_fast = bind(fast_fac, 15);
  future<int> f_slow = bind(slow_fac, 15);
  future<int> f      = f_fast | f_slow;

  cout << f() << endl;

  return 1;
}

For seamless integration with existing code futures provide a second syntax for joining:

future<int> f = bind(fac, 15);

cout << f << endl;

For future<T> the cast operator operator T() is overloaded to work like the function call operator.

Copyright © 2005 Thorsten Schütt

PrevUpHomeNext