Boost logo

Boost Users :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2006-10-12 19:52:26


On Oct 11, 2006, at 5:19 PM, Peter Dimov wrote:

>> 1. I have an application that creates lots of relatively short-lived
>> threads. When a thread is created I store the handle in an array, and
>> at regular intervals, I remove completed threads from the array by
>> checking the thread state via ::GetExitCodeThread. The application
>> runs 24/7 so I don't want an array containing thousands of "dead"
>> handles.
>>
>> I thought I'd replace this code with a boost::thread_group, but I
>> cannot see any way to remove completed threads from the internal
>> list. This means the std::list used by boost::thread_group would
>> keep on increasing in size until the application exits, which I want
>> to avoid. If I decide to roll my own thread group code, how can I
>> check if a boost::thread is still active or not?
>
> You can't.
>
> Interesting timing; I submitted a proposal for a threading API to
> the C++
> committee:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2090.html
>
> that lets you do that. You can keep a vector< thread::handle > and
> periodically sweep it using thread::try_join as a predicate. I've been
> having troubles convincing some committee members of its utility,
> though.

For the record, I'm the committee member Peter speaks of here. And
yes, Peter has been having trouble convincing me that a copyable
std::thread is in our best interest for C++0X.

However I'm fully convinced of the utility of
std::vector<std::thread>. In C++0X this should require only
movability, not copyability. Containers of threads should be
extremely useful, and I'm aware that the lack of this functionality
for boost::thread is frustrating. C++0X should elegantly lift this
restriction, allowing vector<thread>. I know this doesn't help you
today. But my job is to plan for C++0X, not boost, sorry.

The other functionality you request, thread::try_join(), is not
supported by myself. However I am supporting higher level standard-
supplied objects that do support try_join() (with a different
spelling, but I'm not concerned about the spelling for now). For
example:

std::vector<std::future<void>> v;
...
v.push_back(std::launch_in_thread(some_functional));
...
if (v.back().ready()) // try_join
     // join with it
else
     // do something else

The cost of std::future<void> is approximately the same cost as
Peter's copyable thread with try_join functionality, but
significantly more expensive than today's boost::thread (or my
proposed std::thread, approximately equivalent to boost::thread).
When it is obtained from std::launch_in_thread, there is a one to one
mapping of it to an OS thread and it has "try_join" functionality.
Reference:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html

Therein, you'll also find a std::thread_pool which may be even more
applicable to your design constraints:

std::vector<std::future<void>> v;
std::thread_pool launch_in_pool;
...
v.push_back(launch_in_pool(some_functional));
...
if (v.back().ready()) // try_join
     // join with it
else
     // do something else

In a nutshell, I think the availability of move semantics in C++0X
strongly impacts the multithreading API that should be designed. I
also believe a layered approach is pragmatics. Clients can pay for
only what functionality they need (boost::thread while spartan, is
quite useful, and will become even more so when movable). I'm quite
interested to hear about use cases such as yours to make sure we are
covering these bases, with a minimum of cost, and a maximum of
efficiency/performance across as many platforms as we can manage.

-Howard


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