Boost logo

Boost :

From: Vaclav Vesely (vaclav.vesely_at_[hidden])
Date: 2006-03-24 03:19:25


Christopher Kohlhoff wrote:
> --- Vaclav Vesely <vaclav.vesely_at_[hidden]> wrote:
...
>> I've written ASIO background_thread class which calls
>> arbitrary functions in a background thread. If you find it
>> useful, you can add it to examples. After some refining it may
>> be even added to the ASIO library.
...
> Actually I think there may be a way to simplify your code here -
> assuming I correctly understand what you're trying to do.
>
> The code seems to use the data members m_has_work and
> m_has_work_condition to keep restarting the demuxer::run()
> function whenever it has new work to do. The worker thread waits
> on the condition if the demuxer doesn't have any work to do.
...
Not exactly. The worker thread stops when there is no work to do and
async_run it's again if it's not running.

However I think now, that your solution with a work thread permanently
running is better. The reworked example is attached.

Regards,
Vaclav


#include <iostream>
#include "boost/asio.hpp"
#include "boost/bind.hpp"
#include "boost/date_time/posix_time/posix_time.hpp"
#include "boost/thread.hpp"

//-----------------------------------------------------------------------------

template<typename Demuxer>
class async_object
{
public:
    typedef Demuxer demuxer_type;

public:

    async_object(demuxer_type& demuxer):
        m_demuxer(demuxer)
    {
    }

    demuxer_type& demuxer()
    {
        return m_demuxer;
    }

protected:
    demuxer_type& m_demuxer;
};

//-----------------------------------------------------------------------------

template<typename Demuxer>
class background_worker:
    public async_object<Demuxer>
{
public:

    background_worker(Demuxer& demuxer):
        async_object(demuxer),
        m_work_demuxer(),
        m_dummy_work(new boost::asio::demuxer::work(m_work_demuxer))
    {
    }

    ~background_worker()
    {
        m_dummy_work.reset();
        if(m_work_thread)
            m_work_thread->join();
    }

private:

    template<typename Function, typename Handler>
    class run_proc
    {
    public:

        run_proc(demuxer_type& demuxer, Function function, Handler handler):
            m_demuxer(demuxer),
            m_work(demuxer),
            m_function(function),
            m_handler(handler)
        {
        }

        void operator()()
        {
            m_function();
            m_demuxer.post(m_handler);
        }

    private:
        demuxer_type& m_demuxer;
        typename demuxer_type::work m_work;
        Function m_function;
        Handler m_handler;
    };

public:

    template<typename Function, typename Handler>
    void async_run(Function function, Handler handler)
    {
        m_work_demuxer.post(run_proc<Function, Handler>(m_demuxer, function,
            handler));
        if(!m_work_thread)
        {
            m_work_thread.reset(new boost::thread(boost::bind(
                &background_worker::work_thread_proc, this)));
        }
    }

private:

    void work_thread_proc()
    {
        m_work_demuxer.run();
    }

private:
    boost::asio::demuxer m_work_demuxer;
    boost::scoped_ptr<boost::thread> m_work_thread;
    boost::scoped_ptr<boost::asio::demuxer::work> m_dummy_work;
};

//-----------------------------------------------------------------------------

boost::mutex cout_mutex;

void wait(int seconds)
{
    {
        boost::mutex::scoped_lock lock(cout_mutex);
        std::cout << "Wait for " << seconds << " seconds" << std::endl;
    }
    boost::xtime xt;
    boost::xtime_get(&xt, boost::TIME_UTC);
    xt.sec += seconds;
    boost::thread::sleep(xt);
}

void wait_finished()
{
    {
        boost::mutex::scoped_lock lock(cout_mutex);
        std::cout << "Waiting finished." << std::endl;
    }
}

//-----------------------------------------------------------------------------

void main()
{
    boost::asio::demuxer demuxer;
    background_worker<boost::asio::demuxer> bg_thread(demuxer);
    bg_thread.async_run(boost::bind(wait, 1), wait_finished);
    bg_thread.async_run(boost::bind(wait, 1), wait_finished);
    demuxer.run();

    bg_thread.async_run(boost::bind(wait, 1), wait_finished);
    demuxer.reset();
    demuxer.run();
}

//-----------------------------------------------------------------------------


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk