Boost logo

Boost Users :

Subject: Re: [Boost-users] [Threads] How to keep number of running thread constant, performing different operations
From: Lars Viklund (zao_at_[hidden])
Date: 2011-06-17 09:06:41


Comments inline.

On Fri, Jun 17, 2011 at 01:33:02PM +0200, Alessandro Candini wrote:
> On 17/06/11 12:39, Lars Viklund wrote:
>> ---8<---
>> asio::io_service io;
>> scoped_ptr<asio::io_service::work> work(new asio::io_service::work(io));

An io_service acts as the hub and dispatcher of completion handlers,
typically used for network communication but can also be used for
invoking functions on any thread that services the io_service.

The 'work' object is needed to pretend that there are pending operations
that the io_service is not aware of. If an io_service is out of work, it
returns from the run() functions, which we do not want to do until we're
done.

>> boost::thread_group tg;
>> auto N = boost::thread::hardware_concurrency();

A thread_group is part of Boost.Thread and lets you create and join
groups of threads. hardware_concurrency() simply counts the number of
physical processors you have, so it's a good guess to base the number of
worker threads on.

>> for (unsigned i = 0; i< N; ++i)
>> tg.create_thread(boost::bind(&asio::io_service::run, boost::ref(io));

io_service::run() blocks until the service is out of work, and can be
run in as many threads as you want. There's also single-shot variants
and polling variants of it.

>> io.post(some_task);
>> io.post(some_other_task);

io_service::post() takes something callable with the signature
`void ()' and invokes it eventually on any thread that is servicing the
io_service and isn't busy.

>> // invoke io.post whenever you want to enqueue something.
>>
>> // time passes, shutdown time has arrived
>>
>> work.reset();
>> tg.join_all();
>> ---8<---

When we're out of pending handlers, and have destroyed the last work
item, the functions will start to return, and we can join all the
threads.

> Could you please give me a working example as little as possible, to
> better understand all this stuff?

io.post([when_done, other_data]
{
        auto result = compute(other_data);
        when_done(result);
});

This is the form most of my tasks have in the applications where I have
a similar setup. You post a task that when completed informs whoever
cares via a callback.

As Jeroen mentioned on IRC, which I forgot to mention in my first
message, this assumes that tasks are largely independent. If they're not
and you have more concurrent tasks than there's workers, you might end
up with blocking everything, as a handler runs to completion before
returning control to run().

Normally, that's not horribly limiting, as the things you tend to block
on tend to be asynchronous operations that Asio provides, like
reading/writing to sockets, waiting on timers, etc.

I recommend that you read the Asio docs, particularly the prose and
background bits, and take a look at the examples.

Michael Caisse's Boostcon presentation on an Asio Flash XML Server is
quite enlightening as well.

-- 
Lars Viklund | zao_at_[hidden]

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