Some example code, makes use of boost thread, function and bind:
1st - a queue. It accepts "Jobs" which are of type boost::function
More about creating jobs later
#include
#include
#include
#include <list>
// cross-thread job queue. multiple threads can post jobs, one or many
threads can execute jobs.
class job_queue
{
public:
typedef boost::function Job;
private:
boost::mutex mtx_;
boost::condition cnd_;
typedef std::list<Job> Jobs;
Jobs jobs_;
int stop_;
public:
// puts a job into the queue
void post(Job job)
{
boost::mutex::scoped_lock lock(mtx_);
jobs_.push_back(job);
cnd_.notify_one();
}
// pulls one job from the queue, returns false when stopped
bool pull(Job* job)
{
boost::mutex::scoped_lock lock(mtx_);
for(;;)
{ // handle spurious wake-ups
while(!stop_ && jobs_.empty())
cnd_.wait(lock);
if(!jobs_.empty() && 2 != stop_)
{
job->swap(jobs_.front()); // move efficiently, avoiding *job
= jobs.front()
jobs_.pop_front();
return true;
}
else if(stop_)
{
return false;
}
}
}
// make pull() return false
void stop(bool cancel_jobs)
{
boost::mutex::scoped_lock lock(mtx_);
stop_ = 1 + cancel_jobs; // 1 - complete jobs, 2 - cancel jobs
cnd_.notify_all();
}
job_queue() : stop_() {}
~job_queue() { this->stop(true); }
};
//-----------------------------------------------------------------------
2nd, you need to create a thread. The thread accepts a pointer to an
event_queue, and loops indefinitely, pulling jobs off the queue and
executing them.
#include
#include
#include <iostream>
void loop(job_queue* queue)
{
std::cout << __PRETTY_FUNCTION__ << " thread id is: " <<
boost::this_thread::get_id() << std::endl;
job_queue::Job job;
// wait and execute jobs till stopped
while(queue->pull(&job))
job(); // execute the job
}
//-----------------------------------------------------------------------
boost::thread create_thread(job_queue* queue)
{
return boost::thread(boost::bind(loop, queue));
}
//-----------------------------------------------------------------------
Now you need to create jobs and post them to the queue. All jobs are
functors. A functor is something which has the function operator "R
operator()(A...)" - it must be of the form "void ()" for this queue to
accept it. You can create your own functor (example below), or use
boost::bind to create function objects for you. boost::bind can bind class
member functions or free functions or even bind arguments to functors. See
some example usage below:
struct my_functor
{
void operator()()
{
std::cout << "Here I am, doing some work in " << __PRETTY_FUNCTION__
<< " on thread " << boost::this_thread::get_id() <<
std::endl;
}
};
struct my_class
{
void some_function(int b)
{
std::cout << "Here I am, doing some work in " << __PRETTY_FUNCTION__
<< " on thread " << boost::this_thread::get_id()
<< " and my input is " << b << std::endl;
}
};
void free_function_1()
{
std::cout << "Here I am, doing some work in " << __PRETTY_FUNCTION__
<< " on thread " << boost::this_thread::get_id() << std::endl;
}
void free_function_2(char c)
{
std::cout << "Here I am, doing some work in " << __PRETTY_FUNCTION__
<< " on thread " << boost::this_thread::get_id()
<< " and my input is " << c << std::endl;
}
int main()
{
std::cout << __PRETTY_FUNCTION__ << " thread id is: " <<
boost::this_thread::get_id() << std::endl;
job_queue queue;
boost::thread another_thread = create_thread(&queue);
my_functor mf;
my_class mc;
queue.post(mf); // post a function object (functor) to the queue
queue.post(boost::bind(&my_class::some_function, mc, 7)); // bind
creates a functor - binding member function to class instance, and an
argument
queue.post(boost::bind(&free_function_1)); // bind creates a functor
from a free function
queue.post(boost::bind(&free_function_2, 'z')); // bind creates a
functor from a free function and binds the argument
// stop the queue and let it complete all jobs
queue.stop(false);
another_thread.join();
return 0;
}
//-----------------------------------------------------------------------