Boost logo

Boost Users :

Subject: Re: [Boost-users] [thread] Is Boost suitable for this application?
From: Steve Lorimer (steve.lorimer_at_[hidden])
Date: 2010-06-08 04:11:33


Some example code, makes use of boost thread, function and bind:

1st - a queue. It accepts "Jobs" which are of type boost::function<void()>
More about creating jobs later

#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/function.hpp>
#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<void()> 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 <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#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;
}
//-----------------------------------------------------------------------



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net