toast asynchronous library


Detailed Description

Introduction

As Moore's law chugs along single-threaded applications are being left behind. To recapture the benefits of Moore's law we have to start taking advantage of the multicore multiprocessor machines that are finding their way under our desks. To do this quickly one can't make drastic changes to their working code. This library is designed to allow a single threaded application to start taking advantage of mutliple threads right away with very little redesign (it will help if it was already event driven). Additionally, this library should even be useful to an application that is designed to be multithreaded from the ground up.

What does it do?

This library provides a framework for requesting work to be done on a thread. It doesn't matter what the work is, just as long as it's burdensome enough for it to benefit from being done elsewhere. If you have a function that blocks while it calculates or fetches, and you don't want to wait for the answer anymore, you can build a toast::async::request from it (and a callback that should be called when it's done) and ask a toast::async::worker or toast::async::worker_pool to do it and get back to your toast::async::thread_specific_request_queue with an answer.

How do I use it?

The simplest use is toast::async::lockable. Ever wish there were a lockable version of some class T? lockable<T> gives you just that, and ensures that locks are released through use of the RAII pattern (http://en.wikipedia.org/wiki/RAII). lockable<T> doesn't create or manage any threads for you though; it's only a low level building block.

At higher level you can create either create a toast::async::worker or toast::async::worker_pool and pass it work to be done. The push member functions of each accept a toast::async::request which can be any C++ callable object with the signature 'void ()'. You can use boost::bind or std::tr1::bind to make just about any C++ callable object meet this signature. You can also pass the work to a toast::async::worker_pool via toast::async::future() which will give you a toast::async::promise that the work will be completed.

Instead of creating your own toast::async::worker_pool, you can use the toast::async::default_worker_pool() (toast::async::future() will use this by default). The application must first call toast::async::init_default_worker_pool() with some number of threads for this to work. This 'singleton' allows libraries to use a common toast::async::worker_pool so long as they let their clients know it needs initialized. See this example . It is unadvisable for a toast::async::worker or a toast::async::worker_pool to be created by a library as bad things can happen when threads are created prior to main() or with signal masks other than the application expects. Of course you can do this if you know exactly how your library will be used.

A lot can be accomplished with just the above, but it seems likely that you may already have some work that returns a result, and you just want to off load that to a thread. In this case the toast::async::make_request() helper function can be used to build the toast::async::request. In addition to the work you want to off load, you will need a callback function to take the result. When the toast::async::request is run this callback will be bound with the result and pushed on to the toast::async::thread_specific_request_queue for the thread that called toast::async::make_request(). This means that the thread calling toast::async::make_request() must be processing its toast::async::thread_specific_request_queue. If the thread is already a toast::async::worker nothing needs done. If you control the thread, you need to process the toast::async::thread_specific_request_queue (say in your main loop, or event loop). Any library that uses toast::async::make_request() should make it's clients aware so that they are sure to process their toast::async::thread_specific_request_queue. Here is an example .

Other Neat Stuff

The toast::async::locking_queue is used by the toast::async::worker and toast::async::thread_specific_request_queue. It takes care of all queue synchronization as the name suggests, and makes sure as little work as possible is done while locked. You too can use this queue to do custom message passing between threads.

If you want to do something like toast::async::make_request(), but not quite, take a look at it . It just binds the result of toast::async::thread_specific_request_queue::get_push to the toast::async::request in a fancy way so that the result can be sent back to the right place.


Classes

class  toast::async::lockable< T >
 A convenience wrapper around T for synchronizing its use across threads. More...
class  toast::async::locked< T >
 Allows access to a T within a toast::lockable<T>. More...
class  toast::async::locking_queue< T >
 queue for passing data between threads. More...
class  toast::async::promise< T >
 Represents a value that will eventually be defined. More...
class  toast::async::thread_specific_request_queue
 queue for passing requests to specific threads More...
class  toast::async::worker
 represents a thread and provides a way of passing it requests. More...
class  toast::async::worker_pool
 a pool of workers More...

Typedefs

typedef boost::function< void()> toast::async::request
 a request is very simply a function taking and returning nothing.

Functions

template<typename Y>
 toast::async::locked::locked (lockable< Y > &t)
T & toast::async::locked::operator* () const
T * toast::async::locked::operator-> () const
template<typename T>
promise< T > toast::async::future (boost::function< T()> const &f, worker_pool &pool=default_worker_pool())
 Constructs a promise and executes a function that will fulfill the promise in a worker pool.
template<typename T>
request toast::async::make_request (boost::function< T()> const &f, boost::function< void(T)> const &c)
 helper to convert a blocking function, and a callback into a request.
void toast::async::init_default_worker_pool (int number_of_workers, bool complete=false)
 Initialize the default worker_pool singleton.
worker_pool & toast::async::default_worker_pool ()
 The default worker_pool is likely where most requests should be sent.

Friends

class toast::async::lockable::locked


Function Documentation

worker_pool & toast::async::default_worker_pool (  ) 

The default worker_pool is likely where most requests should be sent.

If you use this in a library, be sure to let your clients know they need to call init_default_worker_pool.

Examples:
async/becareful.cpp, and async/callback.cpp.

References TOAST_ASSERT.

template<typename T>
request toast::async::make_request ( boost::function< T()> const &  f,
boost::function< void(T)> const &  c 
) [inline]

helper to convert a blocking function, and a callback into a request.

Take any function that blocks and returns its result, bind all of its arguments, pass this and a callback that will take its result to this function. A request is returned that may be pushed onto to any worker, worker_pool, or thread_specific_request_queue.

When run the request will run the blocking function, and push the callback with argument on to the thread_specific_request_queue for the thread that make_request was called on.

Examples:
async/make_request.cpp.

References toast::async::thread_specific_request_queue::get_push().


SourceForge.net Logo