#include <iostream> #include <list> #include <boost/bind.hpp> #include <boost/thread/condition.hpp> #include <boost/thread/mutex.hpp> #include <toast/async/worker_pool.hpp> #include <toast/async/thread_specific_request_queue.hpp> boost::condition condition; boost::mutex mutex; /* This function will be called when the worker thread pushes the callback * bound with the result of do_work onto the thread_specific_request_queue * for the main thread (the thread that called make_request). This is * actually called on the worker thread and so whatever communication * mechanims it uses to notify the main thread must be syncrhonized. In * this case I'm using a boost::condition, if I had used pipes and polls they * would be synchronized for me by the OS. */ void notify() { boost::mutex::scoped_lock lock(mutex); std::cout << "YooHoo, I've put data on your queue!" << std::endl; condition.notify_one(); } /* This is the work component to be done on the worker thread */ int do_work(int i, int j) { std::cout << "So... you want to know what " << i << " + " << j << " is do ya?" << std::endl; return i + j; } /* This is the callback component to be done back on the main thread * (the thread that called make_request). */ void callback(int i) { std::cout << "How would I have ever known that it was " << i << " without toast::async?" << std::endl; } int main() { toast::async::init_default_worker_pool(3, true); /* ask the thread_specific_request_queue to call this function whenever * something is pushed onto it. */ toast::async::thread_specific_request_queue::on_push(¬ify); /* Here the magical request is made. Look at the make_request.cpp example * to get an idea of how make_request makes all this happen. */ toast::async::request r = toast::async::make_request<int>(boost::bind(&do_work, 5, 12), &callback); toast::async::default_worker_pool().push(r); /* A list is used for efficient transfer of ownership of requests between * 'queues'. Copying lots of data in a critical section is generally not * a good idea, so using the std::list eliminates the need to copy anything. */ std::list<toast::async::request> current; // synchronize the condition variable boost::mutex::scoped_lock lock(mutex); while(current.empty()) { // pop gets everything off the queue and puts it in the list toast::async::thread_specific_request_queue::pop(current); if(current.empty()) condition.wait(lock); } /* generally just calling front like this wouldn't be natural. I know there * is exactly one element though, so I look at it and call it's operator(). */ current.front()(); }